diff --git a/bluesky/.doctr-files b/bluesky/.doctr-files deleted file mode 100644 index 1312def1a6..0000000000 --- a/bluesky/.doctr-files +++ /dev/null @@ -1,615 +0,0 @@ -bluesky/_images/callbacks-1.png -bluesky/_images/callbacks-2.png -bluesky/_images/callbacks-3.png -bluesky/_images/callbacks-4.png -bluesky/_images/callbacks-5.png -bluesky/_images/callbacks-6.png -bluesky/_images/callbacks-7.png -bluesky/_images/callbacks-8.png -bluesky/_images/plans-1.png -bluesky/_images/plans-2.png -bluesky/_images/plans-3.png -bluesky/_images/plans-4.png -bluesky/_images/plans-5.png -bluesky/_images/plans-6.png -bluesky/_images/tutorial-1.png -bluesky/_images/tutorial-2.png -bluesky/_images/tutorial-3.png -bluesky/_images/tutorial-4.png -bluesky/_images/tutorial-5.png -bluesky/_images/tutorial-6.png -bluesky/_modules/bluesky/bundlers.html -bluesky/_modules/bluesky/callbacks/best_effort.html -bluesky/_modules/bluesky/callbacks/broker.html -bluesky/_modules/bluesky/callbacks/core.html -bluesky/_modules/bluesky/callbacks/fitting.html -bluesky/_modules/bluesky/callbacks/mpl_plotting.html -bluesky/_modules/bluesky/callbacks/olog.html -bluesky/_modules/bluesky/callbacks/stream.html -bluesky/_modules/bluesky/callbacks/zmq.html -bluesky/_modules/bluesky/log.html -bluesky/_modules/bluesky/plan_stubs.html -bluesky/_modules/bluesky/plans.html -bluesky/_modules/bluesky/preprocessors.html -bluesky/_modules/bluesky/run_engine.html -bluesky/_modules/bluesky/simulators.html -bluesky/_modules/bluesky/suspenders.html -bluesky/_modules/bluesky/utils.html -bluesky/_modules/index.html -bluesky/_sources/api_changes.rst.txt -bluesky/_sources/appendix.rst.txt -bluesky/_sources/async.rst.txt -bluesky/_sources/callbacks.rst.txt -bluesky/_sources/comparison-with-spec.rst.txt -bluesky/_sources/debugging.rst.txt -bluesky/_sources/documents.rst.txt -bluesky/_sources/event_descriptors.rst.txt -bluesky/_sources/from-pyepics-to-bluesky.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.backstop_collect.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_checkpoint.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_monitors.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.close_run.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.collect.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.complete.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.configure.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.create.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.drop.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.kickoff.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.monitor.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.open_run.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.read.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.record_interruption.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state_coro.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.restore_monitors.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.rewind.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.save.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.suspend_monitors.rst.txt -bluesky/_sources/generated/bluesky.bundlers.RunBundler.unmonitor.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_baseline.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_heading.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_plots.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_table.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_baseline.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_heading.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_plots.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_table.rst.txt -bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.abs_set.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.broadcast_msg.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.caching_repeater.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.checkpoint.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.clear_checkpoint.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.close_run.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.collect.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.complete.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.configure.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.create.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.deferred_pause.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.drop.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.input_plan.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.install_suspender.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.kickoff.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.monitor.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.move_per_step.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.mv.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.mvr.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.null.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.one_1d_step.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.one_nd_step.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.one_shot.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.open_run.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.pause.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.rd.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.read.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.rel_set.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.remove_suspender.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.repeat.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.repeater.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.save.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.sleep.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.stage.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.stop.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.subscribe.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.trigger.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.trigger_and_read.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.unmonitor.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.unstage.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.unsubscribe.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.wait.rst.txt -bluesky/_sources/generated/bluesky.plan_stubs.wait_for.rst.txt -bluesky/_sources/generated/bluesky.plans.adaptive_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.count.rst.txt -bluesky/_sources/generated/bluesky.plans.fly.rst.txt -bluesky/_sources/generated/bluesky.plans.grid_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.list_grid_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.list_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.log_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.ramp_plan.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_adaptive_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_grid_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_list_grid_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_list_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_log_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_scan.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_spiral.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_spiral_fermat.rst.txt -bluesky/_sources/generated/bluesky.plans.rel_spiral_square.rst.txt -bluesky/_sources/generated/bluesky.plans.scan.rst.txt -bluesky/_sources/generated/bluesky.plans.scan_nd.rst.txt -bluesky/_sources/generated/bluesky.plans.spiral.rst.txt -bluesky/_sources/generated/bluesky.plans.spiral_fermat.rst.txt -bluesky/_sources/generated/bluesky.plans.spiral_square.rst.txt -bluesky/_sources/generated/bluesky.plans.tune_centroid.rst.txt -bluesky/_sources/generated/bluesky.plans.tweak.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.baseline_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.baseline_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.contingency_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.finalize_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.finalize_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.fly_during_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.fly_during_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.inject_md_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.inject_md_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.make_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.monitor_during_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.monitor_during_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.msg_mutator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.pchain.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.plan_mutator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.relative_set_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.relative_set_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.reset_positions_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.reset_positions_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.run_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.run_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.single_gen.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.stage_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.stage_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.subs_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.subs_wrapper.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.suspend_decorator.rst.txt -bluesky/_sources/generated/bluesky.preprocessors.suspend_wrapper.rst.txt -bluesky/_sources/generated/bluesky.run_engine.Dispatcher.process.rst.txt -bluesky/_sources/generated/bluesky.run_engine.Dispatcher.rst.txt -bluesky/_sources/generated/bluesky.run_engine.Dispatcher.subscribe.rst.txt -bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe.rst.txt -bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe_all.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.__call__.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.abort.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.clear_suspenders.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.commands.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.halt.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.install_suspender.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.print_command_registry.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.register_command.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.remove_suspender.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_pause.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_suspend.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.resume.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.stop.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.subscribe.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.unregister_command.rst.txt -bluesky/_sources/generated/bluesky.run_engine.RunEngine.unsubscribe.rst.txt -bluesky/_sources/generated/bluesky.simulators.check_limits.rst.txt -bluesky/_sources/generated/bluesky.simulators.plot_raster_path.rst.txt -bluesky/_sources/generated/bluesky.simulators.summarize_plan.rst.txt -bluesky/_sources/generated/bluesky.suspenders.SuspendBoolHigh.rst.txt -bluesky/_sources/generated/bluesky.suspenders.SuspendBoolLow.rst.txt -bluesky/_sources/generated/bluesky.suspenders.SuspendCeil.rst.txt -bluesky/_sources/generated/bluesky.suspenders.SuspendFloor.rst.txt -bluesky/_sources/generated/bluesky.suspenders.SuspendWhenChanged.rst.txt -bluesky/_sources/generated/bluesky.suspenders.SuspendWhenOutsideBand.rst.txt -bluesky/_sources/generated/bluesky.utils.DefaultDuringTask.rst.txt -bluesky/_sources/generated/bluesky.utils.DuringTask.block.rst.txt -bluesky/_sources/generated/bluesky.utils.DuringTask.rst.txt -bluesky/_sources/generated/bluesky.utils.FailedPause.rst.txt -bluesky/_sources/generated/bluesky.utils.FailedStatus.rst.txt -bluesky/_sources/generated/bluesky.utils.IllegalMessageSequence.rst.txt -bluesky/_sources/generated/bluesky.utils.InvalidCommand.rst.txt -bluesky/_sources/generated/bluesky.utils.Msg.rst.txt -bluesky/_sources/generated/bluesky.utils.NoReplayAllowed.rst.txt -bluesky/_sources/generated/bluesky.utils.PersistentDict.directory.rst.txt -bluesky/_sources/generated/bluesky.utils.PersistentDict.rst.txt -bluesky/_sources/generated/bluesky.utils.PlanHalt.rst.txt -bluesky/_sources/generated/bluesky.utils.ProgressBar.clear.rst.txt -bluesky/_sources/generated/bluesky.utils.ProgressBar.draw.rst.txt -bluesky/_sources/generated/bluesky.utils.ProgressBar.rst.txt -bluesky/_sources/generated/bluesky.utils.ProgressBar.update.rst.txt -bluesky/_sources/generated/bluesky.utils.ProgressBarManager.rst.txt -bluesky/_sources/generated/bluesky.utils.RampFail.rst.txt -bluesky/_sources/generated/bluesky.utils.RequestAbort.rst.txt -bluesky/_sources/generated/bluesky.utils.RequestStop.rst.txt -bluesky/_sources/generated/bluesky.utils.RunEngineControlException.rst.txt -bluesky/_sources/generated/bluesky.utils.RunEngineInterrupted.rst.txt -bluesky/_sources/hardware.rst.txt -bluesky/_sources/index.rst.txt -bluesky/_sources/magics.rst.txt -bluesky/_sources/metadata.rst.txt -bluesky/_sources/msg.rst.txt -bluesky/_sources/multi_run_plans.rst.txt -bluesky/_sources/plans.rst.txt -bluesky/_sources/progress-bar.rst.txt -bluesky/_sources/run_engine.rst.txt -bluesky/_sources/run_engine_api.rst.txt -bluesky/_sources/simulation.rst.txt -bluesky/_sources/state-machine.rst.txt -bluesky/_sources/tutorial.rst.txt -bluesky/_sources/utils.rst.txt -bluesky/_static/basic.css -bluesky/_static/css/badge_only.css -bluesky/_static/css/fonts/Roboto-Slab-Bold.woff -bluesky/_static/css/fonts/Roboto-Slab-Bold.woff2 -bluesky/_static/css/fonts/Roboto-Slab-Regular.woff -bluesky/_static/css/fonts/Roboto-Slab-Regular.woff2 -bluesky/_static/css/fonts/fontawesome-webfont.eot -bluesky/_static/css/fonts/fontawesome-webfont.svg -bluesky/_static/css/fonts/fontawesome-webfont.ttf -bluesky/_static/css/fonts/fontawesome-webfont.woff -bluesky/_static/css/fonts/fontawesome-webfont.woff2 -bluesky/_static/css/fonts/lato-bold-italic.woff -bluesky/_static/css/fonts/lato-bold-italic.woff2 -bluesky/_static/css/fonts/lato-bold.woff -bluesky/_static/css/fonts/lato-bold.woff2 -bluesky/_static/css/fonts/lato-normal-italic.woff -bluesky/_static/css/fonts/lato-normal-italic.woff2 -bluesky/_static/css/fonts/lato-normal.woff -bluesky/_static/css/fonts/lato-normal.woff2 -bluesky/_static/css/theme.css -bluesky/_static/doctools.js -bluesky/_static/documentation_options.js -bluesky/_static/file.png -bluesky/_static/fonts/FontAwesome.otf -bluesky/_static/fonts/Lato/lato-bold.eot -bluesky/_static/fonts/Lato/lato-bold.ttf -bluesky/_static/fonts/Lato/lato-bold.woff -bluesky/_static/fonts/Lato/lato-bold.woff2 -bluesky/_static/fonts/Lato/lato-bolditalic.eot -bluesky/_static/fonts/Lato/lato-bolditalic.ttf -bluesky/_static/fonts/Lato/lato-bolditalic.woff -bluesky/_static/fonts/Lato/lato-bolditalic.woff2 -bluesky/_static/fonts/Lato/lato-italic.eot -bluesky/_static/fonts/Lato/lato-italic.ttf -bluesky/_static/fonts/Lato/lato-italic.woff -bluesky/_static/fonts/Lato/lato-italic.woff2 -bluesky/_static/fonts/Lato/lato-regular.eot -bluesky/_static/fonts/Lato/lato-regular.ttf -bluesky/_static/fonts/Lato/lato-regular.woff -bluesky/_static/fonts/Lato/lato-regular.woff2 -bluesky/_static/fonts/Roboto-Slab-Bold.woff -bluesky/_static/fonts/Roboto-Slab-Bold.woff2 -bluesky/_static/fonts/Roboto-Slab-Light.woff -bluesky/_static/fonts/Roboto-Slab-Light.woff2 -bluesky/_static/fonts/Roboto-Slab-Regular.woff -bluesky/_static/fonts/Roboto-Slab-Regular.woff2 -bluesky/_static/fonts/Roboto-Slab-Thin.woff -bluesky/_static/fonts/Roboto-Slab-Thin.woff2 -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff -bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 -bluesky/_static/fonts/fontawesome-webfont.eot -bluesky/_static/fonts/fontawesome-webfont.svg -bluesky/_static/fonts/fontawesome-webfont.ttf -bluesky/_static/fonts/fontawesome-webfont.woff -bluesky/_static/fonts/fontawesome-webfont.woff2 -bluesky/_static/fonts/lato-bold-italic.woff -bluesky/_static/fonts/lato-bold-italic.woff2 -bluesky/_static/fonts/lato-bold.woff -bluesky/_static/fonts/lato-bold.woff2 -bluesky/_static/fonts/lato-normal-italic.woff -bluesky/_static/fonts/lato-normal-italic.woff2 -bluesky/_static/fonts/lato-normal.woff -bluesky/_static/fonts/lato-normal.woff2 -bluesky/_static/jquery-3.5.1.js -bluesky/_static/jquery.js -bluesky/_static/js/badge_only.js -bluesky/_static/js/html5shiv-printshiv.min.js -bluesky/_static/js/html5shiv.min.js -bluesky/_static/js/modernizr.min.js -bluesky/_static/js/theme.js -bluesky/_static/language_data.js -bluesky/_static/minus.png -bluesky/_static/placholder -bluesky/_static/plus.png -bluesky/_static/pygments.css -bluesky/_static/searchtools.js -bluesky/_static/underscore-1.3.1.js -bluesky/_static/underscore.js -bluesky/api_changes.html -bluesky/appendix.html -bluesky/async.html -bluesky/callbacks-1.hires.png -bluesky/callbacks-1.pdf -bluesky/callbacks-1.png -bluesky/callbacks-1.py -bluesky/callbacks-2.hires.png -bluesky/callbacks-2.pdf -bluesky/callbacks-2.png -bluesky/callbacks-2.py -bluesky/callbacks-3.hires.png -bluesky/callbacks-3.pdf -bluesky/callbacks-3.png -bluesky/callbacks-3.py -bluesky/callbacks-4.hires.png -bluesky/callbacks-4.pdf -bluesky/callbacks-4.png -bluesky/callbacks-4.py -bluesky/callbacks-5.hires.png -bluesky/callbacks-5.pdf -bluesky/callbacks-5.png -bluesky/callbacks-5.py -bluesky/callbacks-6.hires.png -bluesky/callbacks-6.pdf -bluesky/callbacks-6.png -bluesky/callbacks-6.py -bluesky/callbacks-7.hires.png -bluesky/callbacks-7.pdf -bluesky/callbacks-7.png -bluesky/callbacks-7.py -bluesky/callbacks-8.hires.png -bluesky/callbacks-8.pdf -bluesky/callbacks-8.png -bluesky/callbacks-8.py -bluesky/callbacks.html -bluesky/comparison-with-spec.html -bluesky/debugging.html -bluesky/documents.html -bluesky/event_descriptors.html -bluesky/from-pyepics-to-bluesky.html -bluesky/generated/bluesky.bundlers.RunBundler.backstop_collect.html -bluesky/generated/bluesky.bundlers.RunBundler.clear_checkpoint.html -bluesky/generated/bluesky.bundlers.RunBundler.clear_monitors.html -bluesky/generated/bluesky.bundlers.RunBundler.close_run.html -bluesky/generated/bluesky.bundlers.RunBundler.collect.html -bluesky/generated/bluesky.bundlers.RunBundler.complete.html -bluesky/generated/bluesky.bundlers.RunBundler.configure.html -bluesky/generated/bluesky.bundlers.RunBundler.create.html -bluesky/generated/bluesky.bundlers.RunBundler.drop.html -bluesky/generated/bluesky.bundlers.RunBundler.html -bluesky/generated/bluesky.bundlers.RunBundler.kickoff.html -bluesky/generated/bluesky.bundlers.RunBundler.monitor.html -bluesky/generated/bluesky.bundlers.RunBundler.open_run.html -bluesky/generated/bluesky.bundlers.RunBundler.read.html -bluesky/generated/bluesky.bundlers.RunBundler.record_interruption.html -bluesky/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state.html -bluesky/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state_coro.html -bluesky/generated/bluesky.bundlers.RunBundler.restore_monitors.html -bluesky/generated/bluesky.bundlers.RunBundler.rewind.html -bluesky/generated/bluesky.bundlers.RunBundler.save.html -bluesky/generated/bluesky.bundlers.RunBundler.suspend_monitors.html -bluesky/generated/bluesky.bundlers.RunBundler.unmonitor.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_baseline.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_heading.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_plots.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_table.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_baseline.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_heading.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_plots.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_table.html -bluesky/generated/bluesky.callbacks.best_effort.BestEffortCallback.html -bluesky/generated/bluesky.plan_stubs.abs_set.html -bluesky/generated/bluesky.plan_stubs.broadcast_msg.html -bluesky/generated/bluesky.plan_stubs.caching_repeater.html -bluesky/generated/bluesky.plan_stubs.checkpoint.html -bluesky/generated/bluesky.plan_stubs.clear_checkpoint.html -bluesky/generated/bluesky.plan_stubs.close_run.html -bluesky/generated/bluesky.plan_stubs.collect.html -bluesky/generated/bluesky.plan_stubs.complete.html -bluesky/generated/bluesky.plan_stubs.configure.html -bluesky/generated/bluesky.plan_stubs.create.html -bluesky/generated/bluesky.plan_stubs.deferred_pause.html -bluesky/generated/bluesky.plan_stubs.drop.html -bluesky/generated/bluesky.plan_stubs.input_plan.html -bluesky/generated/bluesky.plan_stubs.install_suspender.html -bluesky/generated/bluesky.plan_stubs.kickoff.html -bluesky/generated/bluesky.plan_stubs.monitor.html -bluesky/generated/bluesky.plan_stubs.move_per_step.html -bluesky/generated/bluesky.plan_stubs.mv.html -bluesky/generated/bluesky.plan_stubs.mvr.html -bluesky/generated/bluesky.plan_stubs.null.html -bluesky/generated/bluesky.plan_stubs.one_1d_step.html -bluesky/generated/bluesky.plan_stubs.one_nd_step.html -bluesky/generated/bluesky.plan_stubs.one_shot.html -bluesky/generated/bluesky.plan_stubs.open_run.html -bluesky/generated/bluesky.plan_stubs.pause.html -bluesky/generated/bluesky.plan_stubs.rd.html -bluesky/generated/bluesky.plan_stubs.read.html -bluesky/generated/bluesky.plan_stubs.rel_set.html -bluesky/generated/bluesky.plan_stubs.remove_suspender.html -bluesky/generated/bluesky.plan_stubs.repeat.html -bluesky/generated/bluesky.plan_stubs.repeater.html -bluesky/generated/bluesky.plan_stubs.save.html -bluesky/generated/bluesky.plan_stubs.sleep.html -bluesky/generated/bluesky.plan_stubs.stage.html -bluesky/generated/bluesky.plan_stubs.stop.html -bluesky/generated/bluesky.plan_stubs.subscribe.html -bluesky/generated/bluesky.plan_stubs.trigger.html -bluesky/generated/bluesky.plan_stubs.trigger_and_read.html -bluesky/generated/bluesky.plan_stubs.unmonitor.html -bluesky/generated/bluesky.plan_stubs.unstage.html -bluesky/generated/bluesky.plan_stubs.unsubscribe.html -bluesky/generated/bluesky.plan_stubs.wait.html -bluesky/generated/bluesky.plan_stubs.wait_for.html -bluesky/generated/bluesky.plans.adaptive_scan.html -bluesky/generated/bluesky.plans.count.html -bluesky/generated/bluesky.plans.fly.html -bluesky/generated/bluesky.plans.grid_scan.html -bluesky/generated/bluesky.plans.list_grid_scan.html -bluesky/generated/bluesky.plans.list_scan.html -bluesky/generated/bluesky.plans.log_scan.html -bluesky/generated/bluesky.plans.ramp_plan.html -bluesky/generated/bluesky.plans.rel_adaptive_scan.html -bluesky/generated/bluesky.plans.rel_grid_scan.html -bluesky/generated/bluesky.plans.rel_list_grid_scan.html -bluesky/generated/bluesky.plans.rel_list_scan.html -bluesky/generated/bluesky.plans.rel_log_scan.html -bluesky/generated/bluesky.plans.rel_scan.html -bluesky/generated/bluesky.plans.rel_spiral.html -bluesky/generated/bluesky.plans.rel_spiral_fermat.html -bluesky/generated/bluesky.plans.rel_spiral_square.html -bluesky/generated/bluesky.plans.scan.html -bluesky/generated/bluesky.plans.scan_nd.html -bluesky/generated/bluesky.plans.spiral.html -bluesky/generated/bluesky.plans.spiral_fermat.html -bluesky/generated/bluesky.plans.spiral_square.html -bluesky/generated/bluesky.plans.tune_centroid.html -bluesky/generated/bluesky.plans.tweak.html -bluesky/generated/bluesky.preprocessors.baseline_decorator.html -bluesky/generated/bluesky.preprocessors.baseline_wrapper.html -bluesky/generated/bluesky.preprocessors.contingency_wrapper.html -bluesky/generated/bluesky.preprocessors.finalize_decorator.html -bluesky/generated/bluesky.preprocessors.finalize_wrapper.html -bluesky/generated/bluesky.preprocessors.fly_during_decorator.html -bluesky/generated/bluesky.preprocessors.fly_during_wrapper.html -bluesky/generated/bluesky.preprocessors.inject_md_decorator.html -bluesky/generated/bluesky.preprocessors.inject_md_wrapper.html -bluesky/generated/bluesky.preprocessors.lazily_stage_decorator.html -bluesky/generated/bluesky.preprocessors.lazily_stage_wrapper.html -bluesky/generated/bluesky.preprocessors.make_decorator.html -bluesky/generated/bluesky.preprocessors.monitor_during_decorator.html -bluesky/generated/bluesky.preprocessors.monitor_during_wrapper.html -bluesky/generated/bluesky.preprocessors.msg_mutator.html -bluesky/generated/bluesky.preprocessors.pchain.html -bluesky/generated/bluesky.preprocessors.plan_mutator.html -bluesky/generated/bluesky.preprocessors.relative_set_decorator.html -bluesky/generated/bluesky.preprocessors.relative_set_wrapper.html -bluesky/generated/bluesky.preprocessors.reset_positions_decorator.html -bluesky/generated/bluesky.preprocessors.reset_positions_wrapper.html -bluesky/generated/bluesky.preprocessors.run_decorator.html -bluesky/generated/bluesky.preprocessors.run_wrapper.html -bluesky/generated/bluesky.preprocessors.single_gen.html -bluesky/generated/bluesky.preprocessors.stage_decorator.html -bluesky/generated/bluesky.preprocessors.stage_wrapper.html -bluesky/generated/bluesky.preprocessors.subs_decorator.html -bluesky/generated/bluesky.preprocessors.subs_wrapper.html -bluesky/generated/bluesky.preprocessors.suspend_decorator.html -bluesky/generated/bluesky.preprocessors.suspend_wrapper.html -bluesky/generated/bluesky.run_engine.Dispatcher.html -bluesky/generated/bluesky.run_engine.Dispatcher.process.html -bluesky/generated/bluesky.run_engine.Dispatcher.subscribe.html -bluesky/generated/bluesky.run_engine.Dispatcher.unsubscribe.html -bluesky/generated/bluesky.run_engine.Dispatcher.unsubscribe_all.html -bluesky/generated/bluesky.run_engine.RunEngine.__call__.html -bluesky/generated/bluesky.run_engine.RunEngine.abort.html -bluesky/generated/bluesky.run_engine.RunEngine.clear_suspenders.html -bluesky/generated/bluesky.run_engine.RunEngine.commands.html -bluesky/generated/bluesky.run_engine.RunEngine.halt.html -bluesky/generated/bluesky.run_engine.RunEngine.html -bluesky/generated/bluesky.run_engine.RunEngine.install_suspender.html -bluesky/generated/bluesky.run_engine.RunEngine.print_command_registry.html -bluesky/generated/bluesky.run_engine.RunEngine.register_command.html -bluesky/generated/bluesky.run_engine.RunEngine.remove_suspender.html -bluesky/generated/bluesky.run_engine.RunEngine.request_pause.html -bluesky/generated/bluesky.run_engine.RunEngine.request_suspend.html -bluesky/generated/bluesky.run_engine.RunEngine.resume.html -bluesky/generated/bluesky.run_engine.RunEngine.stop.html -bluesky/generated/bluesky.run_engine.RunEngine.subscribe.html -bluesky/generated/bluesky.run_engine.RunEngine.unregister_command.html -bluesky/generated/bluesky.run_engine.RunEngine.unsubscribe.html -bluesky/generated/bluesky.simulators.check_limits.html -bluesky/generated/bluesky.simulators.plot_raster_path.html -bluesky/generated/bluesky.simulators.summarize_plan.html -bluesky/generated/bluesky.suspenders.SuspendBoolHigh.html -bluesky/generated/bluesky.suspenders.SuspendBoolLow.html -bluesky/generated/bluesky.suspenders.SuspendCeil.html -bluesky/generated/bluesky.suspenders.SuspendFloor.html -bluesky/generated/bluesky.suspenders.SuspendWhenChanged.html -bluesky/generated/bluesky.suspenders.SuspendWhenOutsideBand.html -bluesky/generated/bluesky.utils.DefaultDuringTask.html -bluesky/generated/bluesky.utils.DuringTask.block.html -bluesky/generated/bluesky.utils.DuringTask.html -bluesky/generated/bluesky.utils.FailedPause.html -bluesky/generated/bluesky.utils.FailedStatus.html -bluesky/generated/bluesky.utils.IllegalMessageSequence.html -bluesky/generated/bluesky.utils.InvalidCommand.html -bluesky/generated/bluesky.utils.Msg.html -bluesky/generated/bluesky.utils.NoReplayAllowed.html -bluesky/generated/bluesky.utils.PersistentDict.directory.html -bluesky/generated/bluesky.utils.PersistentDict.html -bluesky/generated/bluesky.utils.PlanHalt.html -bluesky/generated/bluesky.utils.ProgressBar.clear.html -bluesky/generated/bluesky.utils.ProgressBar.draw.html -bluesky/generated/bluesky.utils.ProgressBar.html -bluesky/generated/bluesky.utils.ProgressBar.update.html -bluesky/generated/bluesky.utils.ProgressBarManager.html -bluesky/generated/bluesky.utils.RampFail.html -bluesky/generated/bluesky.utils.RequestAbort.html -bluesky/generated/bluesky.utils.RequestStop.html -bluesky/generated/bluesky.utils.RunEngineControlException.html -bluesky/generated/bluesky.utils.RunEngineInterrupted.html -bluesky/genindex.html -bluesky/hardware.html -bluesky/index.html -bluesky/magics.html -bluesky/metadata.html -bluesky/msg.html -bluesky/multi_run_plans.html -bluesky/objects.inv -bluesky/plans-1.hires.png -bluesky/plans-1.pdf -bluesky/plans-1.png -bluesky/plans-1.py -bluesky/plans-2.hires.png -bluesky/plans-2.pdf -bluesky/plans-2.png -bluesky/plans-2.py -bluesky/plans-3.hires.png -bluesky/plans-3.pdf -bluesky/plans-3.png -bluesky/plans-3.py -bluesky/plans-4.hires.png -bluesky/plans-4.pdf -bluesky/plans-4.png -bluesky/plans-4.py -bluesky/plans-5.hires.png -bluesky/plans-5.pdf -bluesky/plans-5.png -bluesky/plans-5.py -bluesky/plans-6.hires.png -bluesky/plans-6.pdf -bluesky/plans-6.png -bluesky/plans-6.py -bluesky/plans.html -bluesky/progress-bar.html -bluesky/py-modindex.html -bluesky/run_engine.html -bluesky/run_engine_api.html -bluesky/search.html -bluesky/searchindex.js -bluesky/simulation.html -bluesky/state-machine.html -bluesky/tutorial-1.hires.png -bluesky/tutorial-1.pdf -bluesky/tutorial-1.png -bluesky/tutorial-1.py -bluesky/tutorial-2.hires.png -bluesky/tutorial-2.pdf -bluesky/tutorial-2.png -bluesky/tutorial-2.py -bluesky/tutorial-3.hires.png -bluesky/tutorial-3.pdf -bluesky/tutorial-3.png -bluesky/tutorial-3.py -bluesky/tutorial-4.hires.png -bluesky/tutorial-4.pdf -bluesky/tutorial-4.png -bluesky/tutorial-4.py -bluesky/tutorial-5.hires.png -bluesky/tutorial-5.pdf -bluesky/tutorial-5.png -bluesky/tutorial-5.py -bluesky/tutorial-6.hires.png -bluesky/tutorial-6.pdf -bluesky/tutorial-6.png -bluesky/tutorial-6.py -bluesky/tutorial.html -bluesky/utils.html \ No newline at end of file diff --git a/bluesky/_images/callbacks-1.png b/bluesky/_images/callbacks-1.png deleted file mode 100644 index b0c0a20246..0000000000 Binary files a/bluesky/_images/callbacks-1.png and /dev/null differ diff --git a/bluesky/_images/callbacks-2.png b/bluesky/_images/callbacks-2.png deleted file mode 100644 index 3cd712b108..0000000000 Binary files a/bluesky/_images/callbacks-2.png and /dev/null differ diff --git a/bluesky/_images/callbacks-3.png b/bluesky/_images/callbacks-3.png deleted file mode 100644 index 8835303a66..0000000000 Binary files a/bluesky/_images/callbacks-3.png and /dev/null differ diff --git a/bluesky/_images/callbacks-4.png b/bluesky/_images/callbacks-4.png deleted file mode 100644 index 5783c1ca0f..0000000000 Binary files a/bluesky/_images/callbacks-4.png and /dev/null differ diff --git a/bluesky/_images/callbacks-5.png b/bluesky/_images/callbacks-5.png deleted file mode 100644 index 43b076e400..0000000000 Binary files a/bluesky/_images/callbacks-5.png and /dev/null differ diff --git a/bluesky/_images/callbacks-6.png b/bluesky/_images/callbacks-6.png deleted file mode 100644 index 98bb080a8b..0000000000 Binary files a/bluesky/_images/callbacks-6.png and /dev/null differ diff --git a/bluesky/_images/callbacks-7.png b/bluesky/_images/callbacks-7.png deleted file mode 100644 index a20dc833f9..0000000000 Binary files a/bluesky/_images/callbacks-7.png and /dev/null differ diff --git a/bluesky/_images/callbacks-8.png b/bluesky/_images/callbacks-8.png deleted file mode 100644 index 8a1f3593f7..0000000000 Binary files a/bluesky/_images/callbacks-8.png and /dev/null differ diff --git a/bluesky/_images/grid_in_grid.png b/bluesky/_images/grid_in_grid.png deleted file mode 100644 index 347181f1df..0000000000 Binary files a/bluesky/_images/grid_in_grid.png and /dev/null differ diff --git a/bluesky/_images/plans-1.png b/bluesky/_images/plans-1.png deleted file mode 100644 index 227dc45873..0000000000 Binary files a/bluesky/_images/plans-1.png and /dev/null differ diff --git a/bluesky/_images/plans-2.png b/bluesky/_images/plans-2.png deleted file mode 100644 index 8a1f3593f7..0000000000 Binary files a/bluesky/_images/plans-2.png and /dev/null differ diff --git a/bluesky/_images/plans-3.png b/bluesky/_images/plans-3.png deleted file mode 100644 index a2825ab9b7..0000000000 Binary files a/bluesky/_images/plans-3.png and /dev/null differ diff --git a/bluesky/_images/plans-4.png b/bluesky/_images/plans-4.png deleted file mode 100644 index bb4773c6a3..0000000000 Binary files a/bluesky/_images/plans-4.png and /dev/null differ diff --git a/bluesky/_images/plans-5.png b/bluesky/_images/plans-5.png deleted file mode 100644 index 44c94c8365..0000000000 Binary files a/bluesky/_images/plans-5.png and /dev/null differ diff --git a/bluesky/_images/plans-6.png b/bluesky/_images/plans-6.png deleted file mode 100644 index 4bacd854fc..0000000000 Binary files a/bluesky/_images/plans-6.png and /dev/null differ diff --git a/bluesky/_images/scan_gaussian.png b/bluesky/_images/scan_gaussian.png deleted file mode 100644 index 53b3bedcd4..0000000000 Binary files a/bluesky/_images/scan_gaussian.png and /dev/null differ diff --git a/bluesky/_images/tutorial-1.png b/bluesky/_images/tutorial-1.png deleted file mode 100644 index afd44d7ecd..0000000000 Binary files a/bluesky/_images/tutorial-1.png and /dev/null differ diff --git a/bluesky/_images/tutorial-2.png b/bluesky/_images/tutorial-2.png deleted file mode 100644 index 7fb555e633..0000000000 Binary files a/bluesky/_images/tutorial-2.png and /dev/null differ diff --git a/bluesky/_images/tutorial-3.png b/bluesky/_images/tutorial-3.png deleted file mode 100644 index 4afe61f3c8..0000000000 Binary files a/bluesky/_images/tutorial-3.png and /dev/null differ diff --git a/bluesky/_images/tutorial-4.png b/bluesky/_images/tutorial-4.png deleted file mode 100644 index e1245fe5a5..0000000000 Binary files a/bluesky/_images/tutorial-4.png and /dev/null differ diff --git a/bluesky/_images/tutorial-5.png b/bluesky/_images/tutorial-5.png deleted file mode 100644 index d9fe2e00d1..0000000000 Binary files a/bluesky/_images/tutorial-5.png and /dev/null differ diff --git a/bluesky/_images/tutorial-6.png b/bluesky/_images/tutorial-6.png deleted file mode 100644 index 20942637b9..0000000000 Binary files a/bluesky/_images/tutorial-6.png and /dev/null differ diff --git a/bluesky/_modules/bluesky/bundlers.html b/bluesky/_modules/bluesky/bundlers.html deleted file mode 100644 index e980fd2f22..0000000000 --- a/bluesky/_modules/bluesky/bundlers.html +++ /dev/null @@ -1,980 +0,0 @@ - - - - - - - - - - bluesky.bundlers — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.bundlers
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.bundlers

-from collections import deque
-from itertools import count, tee
-import time as ttime
-from event_model import DocumentNames
-from .log import doc_logger
-from .utils import (
-    new_uid,
-    IllegalMessageSequence,
-    _rearrange_into_parallel_dicts,
-    short_uid,
-    Msg,
-)
-
-
-
[docs]class RunBundler: -
[docs] def __init__(self, md, record_interruptions, emit, emit_sync, log, *, loop): - # state stolen from the RE - self.bundling = False # if we are in the middle of bundling readings - self._bundle_name = None # name given to event descriptor - self._run_start_uid = None # The (future) runstart uid - self._objs_read = deque() # objects read in one Event - self._read_cache = deque() # cache of obj.read() in one Event - self._asset_docs_cache = deque() # cache of obj.collect_asset_docs() - self._describe_cache = dict() # cache of all obj.describe() output - self._config_desc_cache = dict() # " obj.describe_configuration() - self._config_values_cache = dict() # " obj.read_configuration() values - self._config_ts_cache = dict() # " obj.read_configuration() timestamps - self._descriptors = dict() # cache of {name: (objs_frozen_set, doc)} - self._sequence_counters = dict() # a seq_num counter per stream - self._teed_sequence_counters = dict() # for if we redo data-points - self._monitor_params = dict() # cache of {obj: (cb, kwargs)} - self.run_is_open = False - self._uncollected = set() # objects after kickoff(), before collect() - # we expect the RE to take care of the composition - self._md = md - # this is state on the RE, mirror it here rather than refer to - # the parent - self.record_interruptions = record_interruptions - # this is RE.emit, but lifted to this context - self.emit = emit - self.emit_sync = emit_sync - self.log = log - - self.loop = loop
- -
[docs] async def open_run(self, msg): - self.run_is_open = True - self._run_start_uid = new_uid() - self._interruptions_desc_uid = None # uid for a special Event Desc. - self._interruptions_counter = count(1) # seq_num, special Event stream - - doc = dict(uid=self._run_start_uid, time=ttime.time(), **self._md) - await self.emit(DocumentNames.start, doc) - doc_logger.debug("[start] document is emitted (run_uid=%r)", self._run_start_uid, - extra={'doc_name': 'start', - 'run_uid': self._run_start_uid}) - await self.reset_checkpoint_state_coro() - - # Emit an Event Descriptor for recording any interruptions as Events. - if self.record_interruptions: - self._interruptions_desc_uid = new_uid() - dk = {"dtype": "string", "shape": [], "source": "RunEngine"} - interruptions_desc = dict( - time=ttime.time(), - uid=self._interruptions_desc_uid, - name="interruptions", - data_keys={"interruption": dk}, - run_start=self._run_start_uid, - ) - await self.emit(DocumentNames.descriptor, interruptions_desc) - - return self._run_start_uid
- -
[docs] async def close_run(self, msg): - """Instruct the RunEngine to write the RunStop document - - Expected message object is:: - - Msg('close_run', None, exit_status=None, reason=None) - - if *exit_stats* and *reason* are not provided, use the values - stashed on the RE. - """ - if not self.run_is_open: - raise IllegalMessageSequence( - "A 'close_run' message was received but there is no run " - "open. If this occurred after a pause/resume, add " - "a 'checkpoint' message after the 'close_run' message." - ) - self.log.debug("Stopping run %r", self._run_start_uid) - # Clear any uncleared monitoring callbacks. - for obj, (cb, kwargs) in list(self._monitor_params.items()): - obj.clear_sub(cb) - del self._monitor_params[obj] - # Count the number of Events in each stream. - num_events = {} - for bundle_name, counter in self._sequence_counters.items(): - if bundle_name is None: - # rare but possible via Msg('create', name='primary') - continue - num_events[bundle_name] = next(counter) - 1 - reason = msg.kwargs.get("reason", None) - if reason is None: - reason = "" - exit_status = msg.kwargs.get("exit_status", "success") or "success" - - doc = dict( - run_start=self._run_start_uid, - time=ttime.time(), - uid=new_uid(), - exit_status=exit_status, - reason=reason, - num_events=num_events, - ) - await self.emit(DocumentNames.stop, doc) - doc_logger.debug("[stop] document is emitted (run_uid=%r)", self._run_start_uid, - extra={'doc_name': 'stop', - 'run_uid': self._run_start_uid}) - await self.reset_checkpoint_state_coro() - self.run_is_open = False - return doc["run_start"]
- -
[docs] async def create(self, msg): - """Trigger the run engine to start bundling future obj.read() calls for - an Event document - - Expected message object is:: - - Msg('create', None, name='primary') - Msg('create', name='primary') - - Note that the `name` kwarg will be the 'name' field of the resulting - descriptor. So descriptor['name'] = msg.kwargs['name']. - - Also note that changing the 'name' of the Event will create a new - Descriptor document. - """ - if self.bundling: - raise IllegalMessageSequence( - "A second 'create' message is not " - "allowed until the current event " - "bundle is closed with a 'save' or " - "'drop' message." - ) - self._read_cache.clear() - self._asset_docs_cache.clear() - self._objs_read.clear() - self.bundling = True - command, obj, args, kwargs, _ = msg - try: - self._bundle_name = kwargs["name"] - except KeyError: - try: - self._bundle_name, = args - except ValueError: - raise ValueError( - "Msg('create') now requires a stream name, given as " - "Msg('create', name) or Msg('create', name=name)" - ) from None
- -
[docs] async def read(self, msg, reading): - """ - Add a reading to the open event bundle. - - Expected message object is:: - - Msg('read', obj) - """ - if self.bundling: - obj = msg.obj - # if the object is not in the _describe_cache, cache it - if obj not in self._describe_cache: - # Validate that there is no data key name collision. - data_keys = obj.describe() - self._describe_cache[obj] = data_keys - self._config_desc_cache[obj] = obj.describe_configuration() - self._cache_config(obj) - - # check that current read collides with nothing else in - # current event - cur_keys = set(self._describe_cache[obj].keys()) - for read_obj in self._objs_read: - # that is, field names - known_keys = self._describe_cache[read_obj].keys() - if set(known_keys) & cur_keys: - raise ValueError( - f"Data keys (field names) from {obj!r} " - f"collide with those from {read_obj!r}. " - f"The colliding keys are {set(known_keys) & cur_keys}" - ) - - # add this object to the cache of things we have read - self._objs_read.append(obj) - - # Stash the results, which will be emitted the next time _save is - # called --- or never emitted if _drop is called instead. - self._read_cache.append(reading) - # Ask the object for any resource or datum documents is has cached - # and cache them as well. Likewise, these will be emitted if and - # when _save is called. - if hasattr(obj, "collect_asset_docs"): - self._asset_docs_cache.extend( - obj.collect_asset_docs(*msg.args, **msg.kwargs) - ) - - return reading
- - def _cache_config(self, obj): - "Read the object's configuration and cache it." - config_values = {} - config_ts = {} - for key, val in obj.read_configuration().items(): - config_values[key] = val["value"] - config_ts[key] = val["timestamp"] - self._config_values_cache[obj] = config_values - self._config_ts_cache[obj] = config_ts - -
[docs] async def monitor(self, msg): - """ - Monitor a signal. Emit event documents asynchronously. - - A descriptor document is emitted immediately. Then, a closure is - defined that emits Event documents associated with that descriptor - from a separate thread. This process is not related to the main - bundling process (create/read/save). - - Expected message object is:: - - Msg('monitor', obj, **kwargs) - Msg('monitor', obj, name='event-stream-name', **kwargs) - - where kwargs are passed through to ``obj.subscribe()`` - """ - obj = msg.obj - if msg.args: - raise ValueError( - "The 'monitor' Msg does not accept positional " "arguments." - ) - kwargs = dict(msg.kwargs) - name = kwargs.pop("name", short_uid("monitor")) - if obj in self._monitor_params: - raise IllegalMessageSequence( - "A 'monitor' message was sent for {}" - "which is already monitored".format(obj) - ) - descriptor_uid = new_uid() - data_keys = obj.describe() - config = {obj.name: {"data": {}, "timestamps": {}}} - config[obj.name]["data_keys"] = obj.describe_configuration() - for key, val in obj.read_configuration().items(): - config[obj.name]["data"][key] = val["value"] - config[obj.name]["timestamps"][key] = val["timestamp"] - object_keys = {obj.name: list(data_keys)} - hints = {} - if hasattr(obj, "hints"): - hints.update({obj.name: obj.hints}) - desc_doc = dict( - run_start=self._run_start_uid, - time=ttime.time(), - data_keys=data_keys, - uid=descriptor_uid, - configuration=config, - hints=hints, - name=name, - object_keys=object_keys, - ) - doc_logger.debug("[descriptor] document is emitted with name %r containing " - "data keys %r (run_uid=%r)", name, data_keys.keys(), - self._run_start_uid, - extra={'doc_name': 'descriptor', - 'run_uid': self._run_start_uid, - 'data_keys': data_keys.keys()}) - seq_num_counter = count(1) - - def emit_event(*args, **kwargs): - # Ignore the inputs. Use this call as a signal to call read on the - # object, a crude way to be sure we get all the info we need. - data, timestamps = _rearrange_into_parallel_dicts(obj.read()) - doc = dict( - descriptor=descriptor_uid, - time=ttime.time(), - data=data, - timestamps=timestamps, - seq_num=next(seq_num_counter), - uid=new_uid(), - ) - self.emit_sync(DocumentNames.event, doc) - - self._monitor_params[obj] = emit_event, kwargs - await self.emit(DocumentNames.descriptor, desc_doc) - obj.subscribe(emit_event, **kwargs)
- -
[docs] def record_interruption(self, content): - """ - Emit an event in the 'interruptions' event stream. - - If we are not inside a run or if self.record_interruptions is False, - nothing is done. - """ - if self._interruptions_desc_uid is not None: - # We are inside a run and self.record_interruptions is True. - doc = dict( - descriptor=self._interruptions_desc_uid, - time=ttime.time(), - uid=new_uid(), - seq_num=next(self._interruptions_counter), - data={"interruption": content}, - timestamps={"interruption": ttime.time()}, - ) - self.emit_sync(DocumentNames.event, doc)
- -
[docs] def rewind(self): - self._sequence_counters.clear() - self._sequence_counters.update(self._teed_sequence_counters) - # This is needed to 'cancel' an open bundling (e.g. create) if - # the pause happens after a 'checkpoint', after a 'create', but - # before the paired 'save'. - self.bundling = False
- -
[docs] async def unmonitor(self, msg): - """ - Stop monitoring; i.e., remove the callback emitting event documents. - - Expected message object is:: - - Msg('unmonitor', obj) - """ - obj = msg.obj - if obj not in self._monitor_params: - raise IllegalMessageSequence( - f"Cannot 'unmonitor' {obj}; it is not " "being monitored." - ) - cb, kwargs = self._monitor_params[obj] - obj.clear_sub(cb) - del self._monitor_params[obj] - await self.reset_checkpoint_state_coro()
- -
[docs] async def save(self, msg): - """Save the event that is currently being bundled - - Create and emit an Event document containing the data read from devices - in self._objs_read. Emit any Resource and Datum documents cached by - those devices before emitting the Event document. If this is the first - Event of its stream then create and emit the Event Descriptor document - before emitting Resource, Datum, and Event documents. - - Expected message object is:: - - Msg('save') - """ - if not self.bundling: - raise IllegalMessageSequence( - "A 'create' message must be sent, to " - "open an event bundle, before that " - "bundle can be saved with 'save'." - ) - - # Short-circuit if nothing has been read. (Do not create empty Events.) - if not self._objs_read: - self.bundling = False - self._bundle_name = None - return - # The Event Descriptor is uniquely defined by the set of objects - # read in this Event grouping. - objs_read = frozenset(self._objs_read) - - # Event Descriptor key - desc_key = self._bundle_name - - # This is a separate check because it can be reset on resume. - seq_num_key = desc_key - if seq_num_key not in self._sequence_counters: - counter = count(1) - counter_copy1, counter_copy2 = tee(counter) - self._sequence_counters[seq_num_key] = counter_copy1 - self._teed_sequence_counters[seq_num_key] = counter_copy2 - self.bundling = False - self._bundle_name = None - - d_objs, descriptor_doc = self._descriptors.get(desc_key, (None, None)) - if d_objs is not None and d_objs != objs_read: - raise RuntimeError( - "Mismatched objects read, expected {!s}, " - "got {!s}".format(d_objs, objs_read) - ) - if descriptor_doc is None: - # We do not have an Event Descriptor for this set - # so one must be created. - data_keys = {} - config = {} - object_keys = {} - hints = {} - for obj in objs_read: - dks = self._describe_cache[obj] - obj_name = obj.name - # dks is an OrderedDict. Record that order as a list. - object_keys[obj.name] = list(dks) - for field, dk in dks.items(): - dk["object_name"] = obj_name - data_keys.update(dks) - config[obj_name] = {} - config[obj_name]["data"] = self._config_values_cache[obj] - config[obj_name]["timestamps"] = self._config_ts_cache[obj] - config[obj_name]["data_keys"] = self._config_desc_cache[obj] - if hasattr(obj, "hints"): - hints[obj_name] = obj.hints - descriptor_uid = new_uid() - descriptor_doc = dict( - run_start=self._run_start_uid, - time=ttime.time(), - data_keys=data_keys, - uid=descriptor_uid, - configuration=config, - name=desc_key, - hints=hints, - object_keys=object_keys, - ) - await self.emit(DocumentNames.descriptor, descriptor_doc) - doc_logger.debug( - "[descriptor] document emitted with name %r containing " - "data keys %r (run_uid=%r)", - obj_name, - data_keys.keys(), - self._run_start_uid, - extra={ - 'doc_name': 'descriptor', - 'run_uid': self._run_start_uid, - 'data_keys': data_keys.keys()} - ) - self._descriptors[desc_key] = (objs_read, descriptor_doc) - - descriptor_uid = descriptor_doc["uid"] - - # Resource and Datum documents - for resource_or_datum_name, resource_or_datum_doc in self._asset_docs_cache: - # Add a 'run_start' field to resource documents on their way out - # since this field could not have been set correctly before this point. - if resource_or_datum_name == "resource": - resource_or_datum_doc["run_start"] = self._run_start_uid - - doc_logger.debug( - "[%s] document emitted %r", - resource_or_datum_name, - resource_or_datum_doc, - extra={ - "doc_name": resource_or_datum_name, - "run_uid": self._run_start_uid, - "doc": resource_or_datum_doc - } - ) - - await self.emit( - DocumentNames(resource_or_datum_name), - resource_or_datum_doc - ) - - # Event document - seq_num = next(self._sequence_counters[seq_num_key]) - event_uid = new_uid() - # Merge list of readings into single dict. - readings = {k: v for d in self._read_cache for k, v in d.items()} - data, timestamps = _rearrange_into_parallel_dicts(readings) - # Mark all externally-stored data as not filled so that consumers - # know that the corresponding data are identifiers, not dereferenced - # data. - filled = { - k: False - for k, v in self._descriptors[desc_key][1]["data_keys"].items() - if "external" in v - } - event_doc = dict( - descriptor=descriptor_uid, - time=ttime.time(), - data=data, - timestamps=timestamps, - seq_num=seq_num, - uid=event_uid, - filled=filled, - ) - await self.emit(DocumentNames.event, event_doc) - doc_logger.debug( - "[event] document emitted with data keys %r (run_uid=%r)", - data.keys(), - self._run_start_uid, - extra={ - 'doc_name': 'event', - 'run_uid': self._run_start_uid, - 'data_keys': data.keys()} - )
- -
[docs] def clear_monitors(self): - for obj, (cb, kwargs) in list(self._monitor_params.items()): - try: - obj.clear_sub(cb) - except Exception: - self.log.exception("Failed to stop monitoring %r.", obj) - else: - del self._monitor_params[obj]
- -
[docs] def reset_checkpoint_state(self): - - # Keep a safe separate copy of the sequence counters to use if we - # rewind and retake some data points. - for key, counter in list(self._sequence_counters.items()): - counter_copy1, counter_copy2 = tee(counter) - self._sequence_counters[key] = counter_copy1 - self._teed_sequence_counters[key] = counter_copy2
- -
[docs] async def reset_checkpoint_state_coro(self): - self.reset_checkpoint_state()
- -
[docs] async def suspend_monitors(self): - for obj, (cb, kwargs) in self._monitor_params.items(): - obj.clear_sub(cb)
- -
[docs] async def restore_monitors(self): - for obj, (cb, kwargs) in self._monitor_params.items(): - obj.subscribe(cb, **kwargs)
- -
[docs] async def clear_checkpoint(self, msg): - self._teed_sequence_counters.clear()
- -
[docs] async def drop(self, msg): - """Drop the event that is currently being bundled - - Expected message object is:: - - Msg('drop') - """ - if not self.bundling: - raise IllegalMessageSequence( - "A 'create' message must be sent, to " - "open an event bundle, before that " - "bundle can be dropped with 'drop'." - ) - - self.bundling = False - self._bundle_name = None - self.log.debug("Dropped open event bundle")
- -
[docs] async def kickoff(self, msg): - """Start a flyscan object. - - Expected message object is: - - If `flyer_object` has a `kickoff` function that takes no arguments:: - - Msg('kickoff', flyer_object) - Msg('kickoff', flyer_object, group=<name>) - - If *flyer_object* has a ``kickoff`` function that takes - ``(start, stop, steps)`` as its function arguments:: - - Msg('kickoff', flyer_object, start, stop, step) - Msg('kickoff', flyer_object, start, stop, step, group=<name>) - - """ - self._uncollected.add(msg.obj)
- -
[docs] async def complete(self, msg): - """ - Tell a flyer, 'stop collecting, whenever you are ready'. - - The flyer returns a status object. Some flyers respond to this - command by stopping collection and returning a finished status - object immediately. Other flyers finish their given course and - finish whenever they finish, irrespective of when this command is - issued. - - Expected message object is:: - - Msg('complete', flyer, group=<GROUP>) - - where <GROUP> is a hashable identifier. - """ - ...
- -
[docs] async def collect(self, msg): - """ - Collect data cached by a flyer and emit documents. - - Expect message object is - - Msg('collect', collect_obj) - Msg('collect', flyer_object, stream=True, return_payload=False) - """ - collect_obj = msg.obj - - if not self.run_is_open: - # sanity check -- 'kickoff' should catch this and make this - # code path impossible - raise IllegalMessageSequence( - "A 'collect' message was sent but no run is open." - ) - self._uncollected.discard(collect_obj) - - if hasattr(collect_obj, "collect_asset_docs"): - # Resource and Datum documents - for name, doc in collect_obj.collect_asset_docs(): - # Add a 'run_start' field to the resource document on its way out. - if name == "resource": - doc["run_start"] = self._run_start_uid - await self.emit(DocumentNames(name), doc) - - collect_obj_config = {} - if hasattr(collect_obj, "read_configuration"): - doc_logger.debug("reading configuration from %s", collect_obj) - collect_obj_config[collect_obj.name] = { - "data": {}, - "timestamps": {}, - "data_keys": collect_obj.describe_configuration() - } - for config_key, config in collect_obj.read_configuration().items(): - collect_obj_config[collect_obj.name]["data"][config_key] = config["value"] - collect_obj_config[collect_obj.name]["timestamps"][config_key] = config["timestamp"] - else: - doc_logger.debug("%s has no read_configuration method", collect_obj) - - bulk_data = {} - local_descriptors = {} # hashed on objs_read, not (name, objs_read) - # collect_obj.describe_collect() returns a dictionary like this: - # {name_for_desc1: data_keys_for_desc1, - # name_for_desc2: data_keys_for_desc2, ...} - for stream_name, stream_data_keys in collect_obj.describe_collect().items(): - if stream_name not in self._descriptors: - # We do not have an Event Descriptor for this set. - descriptor_uid = new_uid() - hints = {} - if hasattr(collect_obj, "hints"): - hints.update({collect_obj.name: collect_obj.hints}) - doc = dict( - run_start=self._run_start_uid, - time=ttime.time(), - data_keys=stream_data_keys, - uid=descriptor_uid, - name=stream_name, - configuration=collect_obj_config, - hints=hints, - object_keys={collect_obj.name: list(stream_data_keys)}, - ) - await self.emit(DocumentNames.descriptor, doc) - doc_logger.debug("[descriptor] document is emitted with name %r " - "containing data keys %r (run_uid=%r)", stream_name, - stream_data_keys.keys(), self._run_start_uid, - extra={'doc_name': 'descriptor', - 'run_uid': self._run_start_uid, - 'data_keys': stream_data_keys.keys()}) - self._descriptors[stream_name] = (stream_data_keys, doc) - self._sequence_counters[stream_name] = count(1) - else: - objs_read, doc = self._descriptors[stream_name] - if stream_data_keys != objs_read: - raise RuntimeError( - "Mismatched objects read, " - "expected {!s}, " - "got {!s}".format(stream_data_keys, objs_read) - ) - - descriptor_uid = doc["uid"] - local_descriptors[frozenset(stream_data_keys)] = (stream_name, descriptor_uid) - - bulk_data[descriptor_uid] = [] - - # If stream is True, run 'event' subscription per document. - # If stream is False, run 'bulk_events' subscription once. - stream = msg.kwargs.get("stream", False) - # If True, accumulate all the Events in memory and return them at the - # end, providing the plan access to the Events. If False, do not - # accumulate, and return None. - return_payload = msg.kwargs.get('return_payload', True) - payload = [] - - for ev in collect_obj.collect(): - if return_payload: - payload.append(ev) - - objs_read = frozenset(ev["data"]) - stream_name, descriptor_uid = local_descriptors[objs_read] - seq_num = next(self._sequence_counters[stream_name]) - - event_uid = new_uid() - - reading = ev["data"] - for key in ev["data"]: - reading[key] = reading[key] - ev["data"] = reading - ev["descriptor"] = descriptor_uid - ev["seq_num"] = seq_num - ev["uid"] = event_uid - - if stream: - doc_logger.debug("[event] document is emitted with data keys %r (run_uid=%r)", - ev['data'].keys(), self._run_start_uid, - event_uid, - extra={'doc_name': 'event', - 'run_uid': self._run_start_uid, - 'data_keys': ev['data'].keys()}) - await self.emit(DocumentNames.event, ev) - else: - bulk_data[descriptor_uid].append(ev) - - if not stream: - await self.emit(DocumentNames.bulk_events, bulk_data) - doc_logger.debug("[bulk events] document is emitted for descriptors (run_uid=%r)", - self._run_start_uid, - extra={'doc_name': 'bulk_events', - 'run_uid': self._run_start_uid}) - if return_payload: - return payload
- -
[docs] async def backstop_collect(self): - for obj in list(self._uncollected): - try: - await self.collect(Msg("collect", obj)) - except Exception: - self.log.exception("Failed to collect %r.", obj)
- -
[docs] async def configure(self, msg): - """Configure an object - - Expected message object is :: - - Msg('configure', object, *args, **kwargs) - - which results in this call :: - - object.configure(*args, **kwargs) - """ - obj = msg.obj - # Invalidate any event descriptors that include this object. - # New event descriptors, with this new configuration, will - # be created for any future event documents. - for name in list(self._descriptors): - obj_set, _ = self._descriptors[name] - if obj in obj_set: - del self._descriptors[name] - self._cache_config(obj)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/best_effort.html b/bluesky/_modules/bluesky/callbacks/best_effort.html deleted file mode 100644 index c06011bc5a..0000000000 --- a/bluesky/_modules/bluesky/callbacks/best_effort.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - - - - bluesky.callbacks.best_effort — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.best_effort
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.best_effort

-'''
-    Best Effort Callback.
-    For instructions on how to test in a simulated environment please see:
-        tests/interactive/best_effort_cb.py
-'''
-from cycler import cycler
-from datetime import datetime
-from io import StringIO
-import itertools
-import numpy as np
-import matplotlib.pyplot as plt
-from pprint import pformat
-import re
-import sys
-import threading
-import time
-from warnings import warn
-import weakref
-
-from .core import LiveTable, make_class_safe
-from .mpl_plotting import LivePlot, LiveGrid, LiveScatter, QtAwareCallback
-from .fitting import PeakStats
-import logging
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]@make_class_safe(logger=logger) -class BestEffortCallback(QtAwareCallback): -
[docs] def __init__(self, *, fig_factory=None, table_enabled=True, **kwargs): - super().__init__(**kwargs) - # internal state - self._start_doc = None - self._descriptors = {} - self._table = None - self._heading_enabled = True - self._table_enabled = table_enabled - self._baseline_enabled = True - self._plots_enabled = True - # axes supplied from outside - self._fig_factory = fig_factory - # maps descriptor uid to dict which maps data key to LivePlot instance - self._live_plots = {} - self._live_grids = {} - self._live_scatters = {} - self._peak_stats = {} # same structure as live_plots - self._cleanup_motor_heuristic = False - self._stream_names_seen = set() - - # public options - self.overplot = True - self.noplot_streams = ['baseline'] - self.omit_single_point_plot = True - - # public data - self.peaks = PeakResults() - - # hack to handle the bottom border of the table - self._buffer = StringIO() - self._baseline_toggle = True
- -
[docs] def enable_heading(self): - "Print timestamp and IDs at the top of a run." - self._heading_enabled = True
- -
[docs] def disable_heading(self): - "Opposite of enable_heading()" - self._heading_enabled = False
- -
[docs] def enable_table(self): - "Print hinted readings from the 'primary' stream in a LiveTable." - self._table_enabled = True
- -
[docs] def disable_table(self): - "Opposite of enable_table()" - self._table_enabled = False
- -
[docs] def enable_baseline(self): - "Print hinted fields from the 'baseline' stream." - self._baseline_enabled = True
- -
[docs] def disable_baseline(self): - "Opposite of enable_baseline()" - self._baseline_enabled = False
- -
[docs] def enable_plots(self): - "Plot hinted fields from all streams not in ``noplot_streams``." - self._plots_enabled = True
- -
[docs] def disable_plots(self): - "Do not plot anything." - self._plots_enabled = False
- - def __call__(self, name, doc, *args, **kwargs): - if not (self._table_enabled or self._baseline_enabled or - self._plots_enabled): - return - super().__call__(name, doc, *args, **kwargs) - - def start(self, doc): - self.clear() - self._start_doc = doc - self.plan_hints = doc.get('hints', {}) - - # Prepare a guess about the dimensions (independent variables) in case - # we need it. - motors = self._start_doc.get('motors') - if motors is not None: - GUESS = [([motor], 'primary') for motor in motors] - else: - GUESS = [(['time'], 'primary')] - - # Ues the guess if there is not hint about dimensions. - dimensions = self.plan_hints.get('dimensions') - if dimensions is None: - self._cleanup_motor_heuristic = True - dimensions = GUESS - - # We can only cope with all the dimensions belonging to the same - # stream unless we resample. We are not doing to handle that yet. - if len(set(d[1] for d in dimensions)) != 1: - self._cleanup_motor_heuristic = True - dimensions = GUESS # Fall back on our GUESS. - warn("We are ignoring the dimensions hinted because we cannot " - "combine streams.") - - # for each dimension, choose one field only - # the plan can supply a list of fields. It's assumed the first - # of the list is always the one plotted against - self.dim_fields = [fields[0] - for fields, stream_name in dimensions] - - # make distinction between flattened fields and plotted fields - # motivation for this is that when plotting, we find dependent variable - # by finding elements that are not independent variables - self.all_dim_fields = [field - for fields, stream_name in dimensions - for field in fields] - - _, self.dim_stream = dimensions[0] - - # Print heading. - tt = datetime.fromtimestamp(self._start_doc['time']).utctimetuple() - if self._heading_enabled: - print("\n\nTransient Scan ID: {0} Time: {1}".format( - self._start_doc.get('scan_id', ''), - time.strftime("%Y-%m-%d %H:%M:%S", tt))) - print("Persistent Unique Scan ID: '{0}'".format( - self._start_doc['uid'])) - - def descriptor(self, doc): - self._descriptors[doc['uid']] = doc - stream_name = doc.get('name', 'primary') # fall back for old docs - - if stream_name not in self._stream_names_seen: - self._stream_names_seen.add(stream_name) - if self._table_enabled: - print("New stream: {!r}".format(stream_name)) - - columns = hinted_fields(doc) - - # ## This deals with old documents. ## # - - if stream_name == 'primary' and self._cleanup_motor_heuristic: - # We stashed object names in self.dim_fields, which we now need to - # look up the actual fields for. - self._cleanup_motor_heuristic = False - fixed_dim_fields = [] - for obj_name in self.dim_fields: - # Special case: 'time' can be a dim_field, but it's not an - # object name. Just add it directly to the list of fields. - if obj_name == 'time': - fixed_dim_fields.append('time') - continue - try: - fields = doc.get('hints', {}).get(obj_name, {})['fields'] - except KeyError: - fields = doc['object_keys'][obj_name] - fixed_dim_fields.extend(fields) - self.dim_fields = fixed_dim_fields - - # Ensure that no independent variables ('dimensions') are - # duplicated here. - columns = [c for c in columns if c not in self.all_dim_fields] - - # ## DECIDE WHICH KIND OF PLOT CAN BE USED ## # - - plot_data = True - - if not self._plots_enabled: - plot_data = False - if stream_name in self.noplot_streams: - plot_data = False - if not columns: - plot_data = False - if ((self._start_doc.get('num_points') == 1) and - (stream_name == self.dim_stream) and - self.omit_single_point_plot): - plot_data = False - - if plot_data: - - # This is a heuristic approach until we think of how to hint this in a - # generalizable way. - if stream_name == self.dim_stream: - dim_fields = self.dim_fields - else: - dim_fields = ['time'] # 'time' once LivePlot can do that - - # Create a figure or reuse an existing one. - - fig_name = '{} vs {}'.format(' '.join(sorted(columns)), - ' '.join(sorted(dim_fields))) - if self.overplot and len(dim_fields) == 1: - # If any open figure matches 'figname {number}', use it. If there - # are multiple, the most recently touched one will be used. - pat1 = re.compile('^' + fig_name + '$') - pat2 = re.compile('^' + fig_name + r' \d+$') - for label in plt.get_figlabels(): - if pat1.match(label) or pat2.match(label): - fig_name = label - break - else: - if plt.fignum_exists(fig_name): - # Generate a unique name by appending a number. - for number in itertools.count(2): - new_name = '{} {}'.format(fig_name, number) - if not plt.fignum_exists(new_name): - fig_name = new_name - break - ndims = len(dim_fields) - if not 0 < ndims < 3: - # we need 1 or 2 dims to do anything, do not make empty figures - return - - if self._fig_factory: - fig = self._fig_factory(fig_name) - else: - fig = plt.figure(fig_name) - - if not fig.axes: - if len(columns) < 5: - layout = (len(columns), 1) - else: - nrows = ncols = int(np.ceil(np.sqrt(len(columns)))) - while (nrows - 1) * ncols > len(columns): - nrows -= 1 - layout = (nrows, ncols) - if ndims == 1: - share_kwargs = {'sharex': True} - elif ndims == 2: - share_kwargs = {'sharex': True, 'sharey': True} - else: - raise NotImplementedError("we now support 3D?!") - - fig_size = np.array(layout[::-1]) * 5 - fig.set_size_inches(*fig_size) - fig.subplots(*map(int, layout), **share_kwargs) - for ax in fig.axes[len(columns):]: - ax.set_visible(False) - - axes = fig.axes - - # ## LIVE PLOT AND PEAK ANALYSIS ## # - - if ndims == 1: - self._live_plots[doc['uid']] = {} - self._peak_stats[doc['uid']] = {} - x_key, = dim_fields - for y_key, ax in zip(columns, axes): - dtype = doc['data_keys'][y_key]['dtype'] - if dtype not in ('number', 'integer'): - warn("Omitting {} from plot because dtype is {}" - "".format(y_key, dtype)) - continue - # Create an instance of LivePlot and an instance of PeakStats. - live_plot = LivePlotPlusPeaks(y=y_key, x=x_key, ax=ax, - peak_results=self.peaks) - live_plot('start', self._start_doc) - live_plot('descriptor', doc) - peak_stats = PeakStats(x=x_key, y=y_key) - peak_stats('start', self._start_doc) - peak_stats('descriptor', doc) - - # Stash them in state. - self._live_plots[doc['uid']][y_key] = live_plot - self._peak_stats[doc['uid']][y_key] = peak_stats - - for ax in axes[:-1]: - ax.set_xlabel('') - elif ndims == 2: - # Decide whether to use LiveGrid or LiveScatter. LiveScatter is the - # safer one to use, so it is the fallback.. - gridding = self._start_doc.get('hints', {}).get('gridding') - if gridding == 'rectilinear': - self._live_grids[doc['uid']] = {} - slow, fast = dim_fields - try: - extents = self._start_doc['extents'] - shape = self._start_doc['shape'] - except KeyError: - warn("Need both 'shape' and 'extents' in plan metadata to " - "create LiveGrid.") - else: - data_range = np.array([float(np.diff(e)) for e in extents]) - y_step, x_step = data_range / [max(1, s - 1) for s in shape] - adjusted_extent = [extents[1][0] - x_step / 2, - extents[1][1] + x_step / 2, - extents[0][0] - y_step / 2, - extents[0][1] + y_step / 2] - for I_key, ax in zip(columns, axes): - # MAGIC NUMBERS based on what tacaswell thinks looks OK - data_aspect_ratio = np.abs(data_range[1]/data_range[0]) - MAR = 2 - if (1/MAR < data_aspect_ratio < MAR): - aspect = 'equal' - ax.set_aspect(aspect, adjustable='box') - else: - aspect = 'auto' - ax.set_aspect(aspect, adjustable='datalim') - - live_grid = LiveGrid(shape, I_key, - xlabel=fast, ylabel=slow, - extent=adjusted_extent, - aspect=aspect, - ax=ax) - - live_grid('start', self._start_doc) - live_grid('descriptor', doc) - self._live_grids[doc['uid']][I_key] = live_grid - else: - self._live_scatters[doc['uid']] = {} - x_key, y_key = dim_fields - for I_key, ax in zip(columns, axes): - try: - extents = self._start_doc['extents'] - except KeyError: - xlim = ylim = None - else: - xlim, ylim = extents - live_scatter = LiveScatter(x_key, y_key, I_key, - xlim=xlim, ylim=ylim, - # Let clim autoscale. - ax=ax) - live_scatter('start', self._start_doc) - live_scatter('descriptor', doc) - self._live_scatters[doc['uid']][I_key] = live_scatter - - else: - raise NotImplementedError("we do not support 3D+ in BEC yet " - "(and it should have bailed above)") - try: - fig.tight_layout() - except ValueError: - pass - - # ## TABLE ## # - - if stream_name == self.dim_stream: - if self._table_enabled: - # plot everything, independent or dependent variables - self._table = LiveTable(list(self.all_dim_fields) + columns, separator_lines=False) - self._table('start', self._start_doc) - self._table('descriptor', doc) - - def event(self, doc): - descriptor = self._descriptors[doc['descriptor']] - if descriptor.get('name') == 'primary': - if self._table is not None: - self._table('event', doc) - - # Show the baseline readings. - if descriptor.get('name') == 'baseline': - columns = hinted_fields(descriptor) - self._baseline_toggle = not self._baseline_toggle - if self._baseline_toggle: - file = self._buffer - subject = 'End-of-run' - else: - file = sys.stdout - subject = 'Start-of-run' - if self._baseline_enabled: - print('{} baseline readings:'.format(subject), file=file) - border = '+' + '-' * 32 + '+' + '-' * 32 + '+' - print(border, file=file) - for k, v in doc['data'].items(): - if k not in columns: - continue - print('| {:>30} | {:<30} |'.format(k, v), file=file) - print(border, file=file) - - for y_key in doc['data']: - live_plot = self._live_plots.get(doc['descriptor'], {}).get(y_key) - if live_plot is not None: - live_plot('event', doc) - live_grid = self._live_grids.get(doc['descriptor'], {}).get(y_key) - if live_grid is not None: - live_grid('event', doc) - live_sc = self._live_scatters.get(doc['descriptor'], {}).get(y_key) - if live_sc is not None: - live_sc('event', doc) - peak_stats = self._peak_stats.get(doc['descriptor'], {}).get(y_key) - if peak_stats is not None: - peak_stats('event', doc) - - def stop(self, doc): - if self._table is not None: - self._table('stop', doc) - - # Compute peak stats and build results container. - ps_by_key = {} # map y_key to PeakStats instance - for peak_stats in self._peak_stats.values(): - for y_key, ps in peak_stats.items(): - ps('stop', doc) - ps_by_key[y_key] = ps - self.peaks.update(ps_by_key) - - for live_plots in self._live_plots.values(): - for live_plot in live_plots.values(): - live_plot('stop', doc) - - for live_grids in self._live_grids.values(): - for live_grid in live_grids.values(): - live_grid('stop', doc) - - for live_scatters in self._live_scatters.values(): - for live_scatter in live_scatters.values(): - live_scatter('stop', doc) - - if self._baseline_enabled: - # Print baseline below bottom border of table. - self._buffer.seek(0) - print(self._buffer.read()) - print('\n') - - def clear(self): - self._start_doc = None - self._descriptors.clear() - self._stream_names_seen.clear() - self._table = None - self._live_plots.clear() - self._peak_stats.clear() - self._live_grids.clear() - self._live_scatters.clear() - self.peaks.clear() - self._buffer = StringIO() - self._baseline_toggle = True - - def plot_prune_fifo(self, num_lines, x_signal, y_signal): - """ - Find the plot with axes x_signal and y_signal. Replot with only the last *num_lines* lines. - - Example to remove all scans but the last: - >>> bec.plot_prune_fifo(1, m1, noisy) - - Parameters - ---------- - num_lines: int - number of lines (plotted scans) to keep, must be >= 0 - x_signal: object - instance of ophyd.Signal (or subclass), - independent (x) axis - y_signal: object - instance of ophyd.Signal (or subclass), - dependent (y) axis - """ - if num_lines < 0: - emsg = (f"Argument 'num_lines' (given as {num_lines})" - " must be >= 0.") - raise ValueError(emsg) - for liveplot in self._live_plots.values(): - lp = liveplot.get(y_signal.name) - if lp is None or lp.x != x_signal.name or lp.y != y_signal.name: - continue - - # pick out only the lines that contain plot data, - # skipping the lines that show peak centers - lines = [ - tr - for tr in lp.ax.lines - if len(tr._x) != 2 - or len(tr._y) != 2 - or (len(tr._x) == 2 - and tr._x[0] != tr._x[1]) - ] - if len(lines) > num_lines: - keepers = lines[-num_lines:] - for tr in lines: - if tr not in keepers: - tr.remove() - lp.ax.legend() - if num_lines > 0: - lp.update_plot()
- - -class PeakResults: - ATTRS = ('com', 'cen', 'max', 'min', 'fwhm') - - def __init__(self): - for attr in self.ATTRS: - setattr(self, attr, {}) - - def clear(self): - for attr in self.ATTRS: - getattr(self, attr).clear() - - def update(self, ps_dict): - for y_key, ps in ps_dict.items(): - for attr in self.ATTRS: - getattr(self, attr)[y_key] = getattr(ps, attr) - - def __getitem__(self, key): - if key in self.ATTRS: - return getattr(self, key) - raise KeyError("Keys are: {}".format(self.ATTRS)) - - def __repr__(self): - # This is a proper eval-able repr, but with some manually-tweaked - # whitespace to make it easier to prase. - lines = [] - lines.append('{') - for attr in self.ATTRS: - lines.append("'{}':".format(attr)) - for line in pformat(getattr(self, attr), width=1).split('\n'): - lines.append(" {}".format(line)) - lines.append(',') - lines.append('}') - return '\n'.join(lines) - - -class LivePlotPlusPeaks(LivePlot): - # Track state of axes, which may share instances of LivePlotPlusPeaks. - __labeled = weakref.WeakKeyDictionary() # map ax to True/False - __visible = weakref.WeakKeyDictionary() # map ax to True/False - __instances = weakref.WeakKeyDictionary() # map ax to list of instances - - def __init__(self, *args, peak_results, **kwargs): - self.__setup_lock = threading.Lock() - self.__setup_event = threading.Event() - super().__init__(*args, **kwargs) - self.peak_results = peak_results - - def setup(): - # Run this code in start() so that it runs on the correct thread. - with self.__setup_lock: - if self.__setup_event.is_set(): - return - self.__setup_event.set() - ax = self.ax # for brevity - if ax not in self.__visible: - # This is the first instance of LivePlotPlusPeaks on these axes. - # Set up matplotlib event handling. - - self.__visible[ax] = False - - def toggle(event): - if event.key == 'P': - self.__visible[ax] = ~self.__visible[ax] - for instance in self.__instances[ax]: - instance.check_visibility() - - ax.figure.canvas.mpl_connect('key_press_event', toggle) - - if ax not in self.__instances: - self.__instances[ax] = [] - self.__instances[ax].append(self) - self.__arts = None - - self.__setup = setup - - def check_visibility(self): - if self.__visible[self.ax]: - if self.__arts is None: - self.plot_annotations() - else: - for artist in self.__arts: - artist.set_visible(True) - elif self.__arts is not None: - for artist in self.__arts: - artist.set_visible(False) - self.ax.legend(loc='best') - self.ax.figure.canvas.draw_idle() - - def plot_annotations(self): - styles = iter(cycler('color', 'kr')) - vlines = [] - for style, attr in zip(styles, ['cen', 'com']): - val = self.peak_results[attr][self.y] - # Only put labels in this legend once per axis. - if self.ax in self.__labeled: - label = '_no_legend_' - else: - label = attr - vlines.append(self.ax.axvline(val, label=label, **style)) - self.__labeled[self.ax] = None - self.__arts = vlines - - def start(self, doc): - super().start(doc) - self.__setup() - - def stop(self, doc): - self.check_visibility() - super().stop(doc) - - -def hinted_fields(descriptor): - # Figure out which columns to put in the table. - obj_names = list(descriptor['object_keys']) - # We will see if these objects hint at whether - # a subset of their data keys ('fields') are interesting. If they - # did, we'll use those. If these didn't, we know that the RunEngine - # *always* records their complete list of fields, so we can use - # them all unselectively. - columns = [] - for obj_name in obj_names: - try: - fields = descriptor.get('hints', {}).get(obj_name, {})['fields'] - except KeyError: - fields = descriptor['object_keys'][obj_name] - columns.extend(fields) - return columns -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/broker.html b/bluesky/_modules/bluesky/callbacks/broker.html deleted file mode 100644 index 850c046e58..0000000000 --- a/bluesky/_modules/bluesky/callbacks/broker.html +++ /dev/null @@ -1,546 +0,0 @@ - - - - - - - - - - bluesky.callbacks.broker — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.broker
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.broker

-import os
-import time as ttime
-from .core import CallbackBase
-from ..utils import ensure_uid
-import numpy as np
-
-
-class BrokerCallbackBase(CallbackBase):
-    """
-    Base class for callbacks which need filled documents
-
-    Parameters
-    ----------
-    fields: Iterable of str
-        Names of data field in an Event
-    db: Broker instance, optional
-        The Broker instance to pull the data from
-    """
-
-    def __init__(self, fields, *, db=None):
-        self.db = db
-        self.fields = fields
-        self.descriptor_dict = {}
-
-    def clear(self):
-        self.descriptor_dict.clear()
-
-    def stop(self, doc):
-        self.clear()
-
-    def descriptor(self, doc):
-        self.descriptor_dict = {doc['uid']: doc}
-
-    def event(self, doc):
-        # the subset of self.fields that are (1) in the doc and (2) unfilled
-        # and (3) external
-        fields = [field for field in self.fields
-                  if (field in doc['data'] and
-                      not doc.get('filled', {}).get(field) and
-                      'external' in self.descriptor_dict[
-                          doc['descriptor']]['data_keys'][field])]
-        if fields:
-            if self.db is None:
-                raise RuntimeError('Either the data must be pre-loaded or '
-                                   'a Broker instance must be provided '
-                                   'via the db parameter of '
-                                   'BrokerCallbackBase.')
-            res, = self.db.fill_events(
-                events=[doc],
-                descriptors=[self.descriptor_dict[doc['descriptor']]],
-                fields=fields)
-            doc['data'].update(**res['data'])  # modify in place
-
-
-
[docs]class LiveImage(BrokerCallbackBase): - """ - Stream 2D images in a cross-section viewer. - - Parameters - ---------- - field : string - name of data field in an Event - fs: Registry instance - The Registry instance to pull the data from - cmap : str, colormap, or None - color map to use. Defaults to gray - norm : Normalize or None - Normalization function to use - limit_func : callable, optional - function that takes in the image and returns clim values - auto_redraw : bool, optional - interpolation : str, optional - Interpolation method to use. List of valid options can be found in - CrossSection2DView.interpolation - """ - - def __init__(self, field, *, db=None, cmap=None, norm=None, - limit_func=None, auto_redraw=True, interpolation=None, - window_title=None): - from xray_vision.backend.mpl.cross_section_2d import CrossSection - import matplotlib.pyplot as plt - super().__init__((field,), db=db) - fig = plt.figure() - self.field = field - self.cs = CrossSection(fig, cmap, norm, - limit_func, auto_redraw, interpolation) - if window_title: - self.cs._fig.canvas.set_window_title(window_title) - self.cs._fig.show() - - def event(self, doc): - super().event(doc) - data = doc['data'][self.field] - self.update(data) - - def update(self, data): - self.cs.update_image(data) - self.cs._fig.canvas.draw_idle()
- - -def post_run(callback, db, fill=False): - """Trigger a callback to process all the Documents from a run at the end. - - This function does not receive the Document stream during collection. - It retrieves the complete set of Documents from the DataBroker after - collection is complete. - - Parameters - ---------- - callback : callable - Expected signature :: - - def func(doc_name, doc): - pass - - db : Broker - The databroker instance to use - - fill : boolean, optional - Whether to deference externally-stored data in the documents. - False by default. - - Returns - ------- - func : function - a function that accepts a RunStop Document - - Examples - -------- - Print a table with full (lossless) result set at the end of a run. - - >>> table = LiveTable(['det', 'motor']) - >>> RE(scan(motor, [det], [1,2,3]), {'stop': post_run(table)}) - +------------+-------------------+----------------+----------------+ - | seq_num | time | det | motor | - +------------+-------------------+----------------+----------------+ - | 3 | 14:02:32.218348 | 5.00 | 3.00 | - | 2 | 14:02:32.158503 | 5.00 | 2.00 | - | 1 | 14:02:32.099807 | 5.00 | 1.00 | - +------------+-------------------+----------------+----------------+ - - """ - def f(name, doc): - if name != 'stop': - return - uid = ensure_uid(doc['run_start']) - header = db[uid] - for name, doc in header.documents(fill=fill): - callback(name, doc) - # Depending on the order that this callback and the - # databroker-insertion callback were called in, the databroker might - # not yet have the 'stop' document that we currently have, so we'll - # use our copy instead of expecting the header to include one. - if name != 'stop': - callback('stop', doc) - - return f - - -def make_restreamer(callback, db): - """ - Run a callback whenever a uid is updated. - - Parameters - ---------- - callback : callable - expected signature is `f(name, doc)` - - db : Broker - The databroker instance to use - - Example - ------- - Run a callback whenever a uid is updated. - - >>> def f(name, doc): - ... # do stuff - ... - >>> g = make_restreamer(f, db) - - To use this `ophyd.callbacks.LastUidSignal`: - - >>> last_uid_signal.subscribe(g) - """ - def cb(value, **kwargs): - return db.process(db[value], callback) - - return cb - - -def verify_files_saved(name, doc, db): - "This is a brute-force approach. We retrieve all the data." - ttime.sleep(0.1) # Wait for data to be saved. - if name != 'stop': - return - print(" Verifying that all the run's Documents were saved...") - try: - header = db[ensure_uid(doc['run_start'])] - except Exception as e: - print(" Verification Failed! Error: {0}".format(e)) - return - else: - print('\x1b[1A\u2713') # print a checkmark on the previous line - print(" Verifying that all externally-stored files are accessible...") - try: - list(db.get_events(header, fill=True)) - except Exception as e: - print(" Verification Failed! Error: {0}".format(e)) - else: - print('\x1b[1A\u2713') # print a checkmark on the previous line - - -
[docs]class LiveTiffExporter(BrokerCallbackBase): - """ - Save TIFF files. - - Incorporate metadata and data from individual data points in the filenames. - - Parameters - ---------- - field : str - a data key, e.g., 'image' - template : str - A templated file path, where curly brackets will be filled in with - the attributes of 'start', 'event', and (for image stacks) 'i', - a sequential number. - e.g., "dir/scan{start[scan_id]}_by_{start[experimenter]}_{i}.tiff" - dryrun : bool - default to False; if True, do not write any files - overwrite : bool - default to False, raising an OSError if file exists - db : Broker, optional - The databroker instance to use, if not provided use databroker - singleton - - Attributes - ---------- - filenames : list of filenames written in ongoing or most recent run - """ - - def __init__(self, field, template, dryrun=False, overwrite=False, - db=None): - try: - import tifffile - except ImportError: - print("Tifffile is required by this callback. Please install" - "tifffile and then try again." - "\n\n\tpip install tifffile\n\nor\n\n\tconda install " - "tifffile") - raise - else: - # stash a reference so the module is accessible in self._save_image - self._tifffile = tifffile - - try: - import doct - except ImportError: - print('doct is required by LiveTiffExporter') - else: - self._doct = doct - - self.field = field - super().__init__((field,), db=db.fs) - self.template = template - self.dryrun = dryrun - self.overwrite = overwrite - self.filenames = [] - self._start = None - - def _save_image(self, image, filename): - if not self.overwrite: - if os.path.isfile(filename): - raise OSError("There is already a file at {}. Delete " - "it and try again.".format(filename)) - if not self.dryrun: - self._tifffile.imsave(filename, np.asarray(image)) - self.filenames.append(filename) - - def start(self, doc): - self.filenames = [] - # Convert doc from dict into dottable dict, more convenient - # in Python format strings: doc.key == doc['key'] - self._start = self._doct.Document('start', doc) - super().start(doc) - - def event(self, doc): - if self.field not in doc['data']: - return - super().event(doc) - image = np.asarray(doc['data'][self.field]) - if image.ndim == 2: - filename = self.template.format(start=self._start, event=doc) - self._save_image(image, filename) - if image.ndim == 3: - for i, plane in enumerate(image): - filename = self.template.format(i=i, start=self._start, - event=doc) - self._save_image(plane, filename) - - def stop(self, doc): - self._start = None - self.filenames = [] - super().stop(doc)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/core.html b/bluesky/_modules/bluesky/callbacks/core.html deleted file mode 100644 index edf9df09c1..0000000000 --- a/bluesky/_modules/bluesky/callbacks/core.html +++ /dev/null @@ -1,687 +0,0 @@ - - - - - - - - - - bluesky.callbacks.core — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.core
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.core

-"""
-Useful callbacks for the Run Engine
-"""
-from itertools import count
-import warnings
-import os
-
-from collections import deque, namedtuple, OrderedDict
-import time as ttime
-from functools import wraps as _wraps, partial as _partial
-
-from datetime import datetime
-import logging
-from ..utils import ensure_uid
-
-from event_model import DocumentRouter
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]def make_callback_safe(func=None, *, logger=None): - """ - If the wrapped func raises any exceptions, log them but continue. - - This is intended to ensure that any failures in non-critical callbacks do - not interrupt data acquisition. It should *not* be applied to any - critical callbacks, such as ones that perform data-saving, but is well - suited to callbacks that perform non-critical streaming visualization or - data processing. - - To debug the issue causing a failure, it can be convenient to turn this - off and let the failures raise. To do this, set the environment variable - ``BLUESKY_DEBUG_CALLBACKS=1``. - - Parameters - ---------- - func: callable - logger: logging.Logger, optional - - Examples - -------- - - Decorate a callback to make sure it will not interrupt data acquisition if - it fails. - - >>> @make_callback_safe - ... def callback(name, doc): - ... ... - """ - if func is None: - return _partial(make_callback_safe, logger=logger) - - @_wraps(func) - def inner(*args, **kwargs): - try: - return func(*args, **kwargs) - except Exception: - debug_mode = os.environ.get("BLUESKY_DEBUG_CALLBACKS", False) - if logger is not None: - if debug_mode: - msg = f"Exception in {func}" - else: - msg = ( - f"An exception raised in the callback {func} " - "is being suppressed to not interrupt plan " - "execution. To investigate try setting the " - "BLUESKY_DEBUG_CALLBACKS env to '1'" - ) - logger.exception(msg) - if debug_mode: - raise - - return inner
- - -
[docs]def make_class_safe(cls=None, *, to_wrap=None, logger=None): - """ - If the wrapped func raises any exceptions, log them but continue. - - This is intended to ensure that any failures in non-critical callbacks do - not interrupt data acquisition. It should *not* be applied to any - critical callbacks, such as ones that perform data-saving, but is well - suited to callbacks that perform non-critical streaming visualization or - data processing. - - To debug the issue causing a failure, it can be convenient to turn this - off and let the failures raise. To do this, set the environment variable - ``BLUESKY_DEBUG_CALLBACKS=1``. - - Parameters - ---------- - cls: callable - to_wrap: List[String], optional - Names of methods of cls to wrap. Default is ``['__call__']``. - logger: logging.Logger, optional - - Examples - -------- - - Decorate a class to make sure it will not interrupt data acquisition if - it fails. - - >>> @make_class_safe - ... class Callback(event_model.DocumentRouter): - ... ... - """ - - if cls is None: - return _partial(make_class_safe, to_wrap=to_wrap, logger=logger) - - if to_wrap is None: - to_wrap = ['__call__'] - - for f_name in to_wrap: - setattr(cls, f_name, make_callback_safe(getattr(cls, f_name), logger=logger)) - - return cls
- - -class CallbackBase(DocumentRouter): - log = None - - -class CallbackCounter: - "As simple as it sounds: count how many times a callback is called." - # Wrap itertools.count in something we can use as a callback. - def __init__(self): - self.counter = count() - self(None, {}) # Pass a fake doc to prime the counter (start at 1). - - def __call__(self, name, doc): - self.value = next(self.counter) - - -def print_metadata(name, doc): - "Print all fields except uid and time." - for field, value in sorted(doc.items()): - # uid is returned by the RunEngine, and time is self-evident - if field not in ['time', 'uid']: - print('{0}: {1}'.format(field, value)) - - -def collector(field, output): - """ - Build a function that appends data to a list. - - This is useful for testing but not advised for general use. (There is - probably a better way to do whatever you want to do!) - - Parameters - ---------- - field : str - the name of a data field in an Event - output : mutable iterable - such as a list - - Returns - ------- - func : function - expects one argument, an Event dictionary - """ - def f(name, event): - output.append(event['data'][field]) - - return f - - -def format_num(x, max_len=11, pre=5, post=5): - if (abs(x) > 10**pre or abs(x) < 10**-post) and x != 0: - x = '%.{}e'.format(post) % x - else: - x = '%{}.{}f'.format(pre, post) % x - - return x - - -def get_obj_fields(fields): - """ - If fields includes any objects, get their field names using obj.describe() - - ['det1', det_obj] -> ['det1, 'det_obj_field1, 'det_obj_field2']" - """ - string_fields = [] - for field in fields: - if isinstance(field, str): - string_fields.append(field) - else: - try: - field_list = sorted(field.describe().keys()) - except AttributeError: - raise ValueError("Fields must be strings or objects with a " - "'describe' method that return a dict.") - string_fields.extend(field_list) - return string_fields - - -class CollectThenCompute(CallbackBase): - - def __init__(self): - self._start_doc = None - self._stop_doc = None - self._events = deque() - self._descriptors = deque() - - def start(self, doc): - self._start_doc = doc - super().start(doc) - - def descriptor(self, doc): - self._descriptors.append(doc) - super().descriptor(doc) - - def event(self, doc): - self._events.append(doc) - super().event(doc) - - def stop(self, doc): - self._stop_doc = doc - self.compute() - super().stop(doc) - - def reset(self): - self._start_doc = None - self._stop_doc = None - self._events.clear() - self._descriptors.clear() - - def compute(self): - raise NotImplementedError("This method must be defined by a subclass.") - - -
[docs]@make_class_safe(logger=logger) -class LiveTable(CallbackBase): - '''Live updating table - - Parameters - ---------- - fields : list - List of fields to add to the table. - - stream_name : str, optional - The event stream to watch for - - print_header_interval : int, optional - Reprint the header every this many lines, defaults to 50 - - min_width : int, optional - The minimum width is spaces of the data columns. Defaults to 12 - - default_prec : int, optional - Precision to use if it can not be found in descriptor, defaults to 3 - - extra_pad : int, optional - Number of extra spaces to put around the printed data, defaults to 1 - - separator_lines : bool, optional - Add empty lines before and after the printed table, default True - - logbook : callable, optional - Must take a sting as the first positional argument - - def logbook(input_str): - pass - - out : callable, optional - Function to call to 'print' a line. Defaults to `print` - ''' - _FMTLOOKUP = {'s': '{pad}{{{k}: >{width}.{prec}{dtype}}}{pad}', - 'f': '{pad}{{{k}: >{width}.{prec}{dtype}}}{pad}', - 'g': '{pad}{{{k}: >{width}.{prec}{dtype}}}{pad}', - 'd': '{pad}{{{k}: >{width}{dtype}}}{pad}'} - _FMT_MAP = {'number': 'f', - 'integer': 'd', - 'string': 's', - } - _fm_sty = namedtuple('fm_sty', ['width', 'prec', 'dtype']) - water_mark = ("{st[plan_type]} {st[plan_name]} ['{st[uid]:.8s}'] " - "(scan num: {st[scan_id]})") - ev_time_key = 'SUPERLONG_EV_TIMEKEY_THAT_I_REALLY_HOPE_NEVER_CLASHES' - - def __init__(self, fields, *, stream_name='primary', - print_header_interval=50, - min_width=12, default_prec=3, extra_pad=1, separator_lines=True, - logbook=None, out=print): - super().__init__() - self._header_interval = print_header_interval - # expand objects - self._fields = get_obj_fields(fields) - self._stream = stream_name - self._start = None - self._stop = None - self._descriptors = set() - self._pad_len = extra_pad - self._extra_pad = ' ' * extra_pad - self._min_width = min_width - self._default_prec = default_prec - self._separator_lines = separator_lines - self._format_info = OrderedDict([ - ('seq_num', self._fm_sty(10 + self._pad_len, '', 'd')), - (self.ev_time_key, self._fm_sty(10 + 2 * extra_pad, 10, 's')) - ]) - self._rows = [] - self.logbook = logbook - self._sep_format = None - self._out = out - - def descriptor(self, doc): - - def patch_up_precision(p): - try: - return int(p) - except (TypeError, ValueError): - return self._default_prec - - if doc['name'] != self._stream: - return - - self._descriptors.add(doc['uid']) - - dk = doc['data_keys'] - for k in self._fields: - width = max(self._min_width, - len(k) + 2, - self._default_prec + 1 + 2 * self._pad_len) - try: - dk_entry = dk[k] - except KeyError: - # this descriptor does not know about this key - continue - - if dk_entry['dtype'] not in self._FMT_MAP: - warnings.warn("The key {} will be skipped because LiveTable " - "does not know how to display the dtype {}" - "".format(k, dk_entry['dtype'])) - continue - - prec = patch_up_precision(dk_entry.get('precision', - self._default_prec)) - fmt = self._fm_sty(width=width, - prec=prec, - dtype=self._FMT_MAP[dk_entry['dtype']]) - - self._format_info[k] = fmt - - self._sep_format = ('+' + - '+'.join('-' * f.width - for f in self._format_info.values()) + - '+') - self._main_fmnt = '|'.join( - '{{: >{w}}}{pad}'.format(w=f.width - self._pad_len, - pad=' ' * self._pad_len) - for f in self._format_info.values()) - headings = [k if k != self.ev_time_key else 'time' - for k in self._format_info] - self._header = ('|' + - self._main_fmnt.format(*headings) + - '|' - ) - self._data_formats = OrderedDict( - (k, self._FMTLOOKUP[f.dtype].format( - k=f'h{str(hash(k))}', - width=f.width-2*self._pad_len, - prec=f.prec, dtype=f.dtype, - pad=self._extra_pad)) - for k, f in self._format_info.items()) - - self._count = 0 - - if self._separator_lines: - self._print("\n") - self._print(self._sep_format) - self._print(self._header) - self._print(self._sep_format) - super().descriptor(doc) - - def event(self, doc): - try: - # shallow copy so we can mutate - if ensure_uid(doc['descriptor']) not in self._descriptors: - return - data = dict(doc['data']) - self._count += 1 - if not self._count % self._header_interval: - self._print(self._sep_format) - self._print(self._header) - self._print(self._sep_format) - fmt_time = str(datetime.fromtimestamp(doc['time']).time()) - data[self.ev_time_key] = fmt_time - data['seq_num'] = doc['seq_num'] - cols = [f.format(**{f'h{str(hash(k))}': data[k]}) - # Show data[k] if k exists in this Event and is 'filled'. - # (The latter is only applicable if the data is - # externally-stored -- hence the fallback to `True`.) - if ((k in data) and doc.get('filled', {}).get(k, True)) - # Otherwise use a placeholder of whitespace. - else ' ' * self._format_info[k].width - for k, f in self._data_formats.items()] - self._print('|' + '|'.join(cols) + '|') - except Exception as ex: - if self.log is not None: - self.log.exception(ex) - self._print('{{k:*^{self._min_width}}}' - .format(self=self) - .format(k=' failed to format row ')) - if os.environ.get('BLUESKY_DEBUG_CALLBACKS', False): - raise ex - super().event(doc) - - def stop(self, doc): - if ensure_uid(doc['run_start']) != self._start['uid']: - return - - # This sleep is just cosmetic. It improves the odds that the bottom - # border is not printed until all the rows from events are printed, - # avoiding this ugly scenario: - # - # | 4 | 22:08:56.7 | 0.000 | - # +-----------+------------+------------+ - # generator scan ['6d3f71'] (scan num: 1) - # Out[2]: | 5 | 22:08:56.8 | 0.000 | - ttime.sleep(0.1) - - if self._sep_format is not None: - self._print(self._sep_format) - self._stop = doc - - wm = self.water_mark.format(st=self._start) - self._out(wm) - if self.logbook: - self.logbook('\n'.join([wm] + self._rows)) - if self._separator_lines: - self._print("\n") - super().stop(doc) - - def start(self, doc): - self._rows = [] - self._start = doc - self._stop = None - self._sep_format = None - super().start(doc) - - def _print(self, out_str): - self._rows.append(out_str) - self._out(out_str)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/fitting.html b/bluesky/_modules/bluesky/callbacks/fitting.html deleted file mode 100644 index 48f4123ad2..0000000000 --- a/bluesky/_modules/bluesky/callbacks/fitting.html +++ /dev/null @@ -1,537 +0,0 @@ - - - - - - - - - - bluesky.callbacks.fitting — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.fitting
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.fitting

-import warnings
-import numpy as np
-
-from .core import CallbackBase, CollectThenCompute
-
-
-
[docs]class LiveFit(CallbackBase): - """ - Fit a model to data using nonlinear least-squares minimization. - - Parameters - ---------- - model : lmfit.Model - y : string - name of the field in the Event document that is the dependent variable - independent_vars : dict - map the independent variable name(s) in the model to the field(s) - in the Event document; e.g., ``{'x': 'motor'}`` - init_guess : dict, optional - initial guesses for other values, if expected by model; - e.g., ``{'sigma': 1}`` - update_every : int or None, optional - How often to recompute the fit. If `None`, do not compute until the - end. Default is 1 (recompute after each new point). - - Attributes - ---------- - result : lmfit.ModelResult - """ - def __init__(self, model, y, independent_vars, init_guess=None, *, - update_every=1): - self.ydata = [] - self.independent_vars_data = {} - self.__stale = False - self.result = None - self._model = model - self.y = y - self.independent_vars = independent_vars - if init_guess is None: - init_guess = {} - self.init_guess = init_guess - self.update_every = update_every - - @property - def model(self): - # Make this a property so it can't be updated. - return self._model - - @property - def independent_vars(self): - return self._independent_vars - - @independent_vars.setter - def independent_vars(self, val): - if set(val) != set(self.model.independent_vars): - raise ValueError("keys {} must match the independent variables in " - "the model " - "{}".format(set(val), - set(self.model.independent_vars))) - self._independent_vars = val - self.independent_vars_data.clear() - self.independent_vars_data.update({k: [] for k in val}) - self._reset() - - def _reset(self): - self.result = None - self.__stale = False - self.ydata.clear() - for v in self.independent_vars_data.values(): - v.clear() - - def start(self, doc): - self._reset() - super().start(doc) - - def event(self, doc): - if self.y not in doc['data']: - return - y = doc['data'][self.y] - idv = {k: doc['data'][v] for k, v in self.independent_vars.items()} - - # Always stash the data for the next time the fit is updated. - self.update_caches(y, idv) - self.__stale = True - - # Maybe update the fit or maybe wait. - if self.update_every is not None: - i = len(self.ydata) - N = len(self.model.param_names) - if i < N: - # not enough points to fit yet - pass - elif (i == N) or ((i - 1) % self.update_every == 0): - self.update_fit() - super().event(doc) - - def stop(self, doc): - # Update the fit if it was not updated by the last event. - if self.__stale: - self.update_fit() - super().stop(doc) - - def update_caches(self, y, independent_vars): - self.ydata.append(y) - for k, v in self.independent_vars_data.items(): - v.append(independent_vars[k]) - - def update_fit(self): - N = len(self.model.param_names) - if len(self.ydata) < N: - warnings.warn("LiveFitPlot cannot update fit until there are at least {} " - "data points".format(N)) - else: - kwargs = {} - kwargs.update(self.independent_vars_data) - kwargs.update(self.init_guess) - self.result = self.model.fit(self.ydata, **kwargs) - self.__stale = False
- - -# This function is vendored from scipy v0.16.1 to avoid adding a scipy -# dependency just for one Python function - - -def center_of_mass(input, labels=None, index=None): - """ - Calculate the center of mass of the values of an array at labels. - Parameters - ---------- - input : ndarray - Data from which to calculate center-of-mass. - labels : ndarray, optional - Labels for objects in `input`, as generated by `ndimage.label`. - Only used with `index`. Dimensions must be the same as `input`. - index : int or sequence of ints, optional - Labels for which to calculate centers-of-mass. If not specified, - all labels greater than zero are used. Only used with `labels`. - Returns - ------- - center_of_mass : tuple, or list of tuples - Coordinates of centers-of-mass. - Examples - -------- - >>> a = np.array(([0,0,0,0], - [0,1,1,0], - [0,1,1,0], - [0,1,1,0])) - >>> from scipy import ndimage - >>> ndimage.measurements.center_of_mass(a) - (2.0, 1.5) - Calculation of multiple objects in an image - >>> b = np.array(([0,1,1,0], - [0,1,0,0], - [0,0,0,0], - [0,0,1,1], - [0,0,1,1])) - >>> lbl = ndimage.label(b)[0] - >>> ndimage.measurements.center_of_mass(b, lbl, [1,2]) - [(0.33333333333333331, 1.3333333333333333), (3.5, 2.5)] - """ - normalizer = np.sum(input, labels, index) - grids = np.ogrid[[slice(0, i) for i in input.shape]] - - results = [ - np.sum(input * grids[dir].astype(float), labels, index) / normalizer - for dir in range(input.ndim)] - - if np.isscalar(results[0]): - return tuple(results) - - return [tuple(v) for v in np.array(results).T] - - -
[docs]class PeakStats(CollectThenCompute): - """ - Compute peak statsitics after a run finishes. - - Results are stored in the attributes. - - Parameters - ---------- - x : string - field name for the x variable (e.g., a motor) - y : string - field name for the y variable (e.g., a detector) - - edge_count : int or None, optional - If not None, number of points at beginning and end to use - for quick and dirty background subtraction. - - Notes - ----- - It is assumed that the two fields, x and y, are recorded in the same - Event stream. - - Attributes - ---------- - com : center of mass - cen : mid-point between half-max points on each side of the peak - max : x location of y maximum - min : x location of y minimum - crossings : crosses between y and middle line, which is - ((np.max(y) + np.min(y)) / 2). Users can estimate FWHM based - on those info. - fwhm : the computed full width half maximum (fwhm) of a peak. - The distance between the first and last crossing is taken to - be the fwhm. - """ - - def __init__(self, x, y, edge_count=None): - self.x = x - self.y = y - self.com = None - self.cen = None - self.max = None - self.min = None - self.crossings = None - self.fwhm = None - self.lin_bkg = None - self._edge_count = edge_count - super().__init__() - - def __getitem__(self, key): - if key in ['com', 'cen', 'max', 'min']: - return getattr(self, key) - else: - raise KeyError - - def compute(self): - "This method is called at run-stop time by the superclass." - # clear all results - self.com = None - self.cen = None - self.max = None - self.min = None - self.crossings = None - self.fwhm = None - self.lin_bkg = None - - x = [] - y = [] - for event in self._events: - try: - _x = event['data'][self.x] - _y = event['data'][self.y] - except KeyError: - pass - else: - x.append(_x) - y.append(_y) - x = np.array(x) - y = np.array(y) - if not len(x): - # nothing to do - return - self.x_data = x - self.y_data = y - if self._edge_count is not None: - left_x = np.mean(x[:self._edge_count]) - left_y = np.mean(y[:self._edge_count]) - - right_x = np.mean(x[-self._edge_count:]) - right_y = np.mean(y[-self._edge_count:]) - - m = (right_y - left_y) / (right_x - left_x) - b = left_y - m * left_x - # don't do this in place to not mess with self.y_data - y = y - (m * x + b) - self.lin_bkg = {'m': m, 'b': b} - - # Compute x value at min and max of y - self.max = x[np.argmax(y)], self.y_data[np.argmax(y)], - self.min = x[np.argmin(y)], self.y_data[np.argmin(y)], - self.com, = np.interp(center_of_mass(y), np.arange(len(x)), x) - mid = (np.max(y) + np.min(y)) / 2 - crossings = np.where(np.diff((y > mid).astype(np.int)))[0] - _cen_list = [] - for cr in crossings.ravel(): - _x = x[cr:cr+2] - _y = y[cr:cr+2] - mid - - dx = np.diff(_x)[0] - dy = np.diff(_y)[0] - m = dy / dx - _cen_list.append((-_y[0] / m) + _x[0]) - - if _cen_list: - self.cen = np.mean(_cen_list) - self.crossings = np.array(_cen_list) - if len(_cen_list) >= 2: - self.fwhm = np.abs(self.crossings[-1] - self.crossings[0], - dtype=float) - # reset y data - y = self.y_data
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/mpl_plotting.html b/bluesky/_modules/bluesky/callbacks/mpl_plotting.html deleted file mode 100644 index b775dac893..0000000000 --- a/bluesky/_modules/bluesky/callbacks/mpl_plotting.html +++ /dev/null @@ -1,939 +0,0 @@ - - - - - - - - - - bluesky.callbacks.mpl_plotting — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.mpl_plotting
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.mpl_plotting

-from collections import ChainMap
-from cycler import cycler
-import numpy as np
-import threading
-import warnings
-import functools
-from .core import CallbackBase, get_obj_fields, make_class_safe
-import logging
-
-logger = logging.getLogger(__name__)
-
-
-# The purpose of initialize_qt_teleporter, _get_teleporter, and QtAwareCallback
-# is to ensure that Qt GUI events are processed on the main thread.
-
-
-def initialize_qt_teleporter():
-    """
-    Set up the bluesky Qt 'teleporter'.
-
-    This makes it safe to instantiate QtAwareCallback from a background thread.
-
-    Raises
-    ------
-    RuntimeError
-        If called from any thread but the main thread
-
-    """
-    if threading.current_thread() is not threading.main_thread():
-        raise RuntimeError(
-            "initialize_qt_teleporter() may only be called from the main "
-            "thread.")
-    _get_teleporter()
-
-
-# use function + LRU cache to hide Matplotib import until needed
-@functools.lru_cache(maxsize=1)
-def _get_teleporter():
-    from matplotlib.backends.qt_compat import QtCore
-
-    if threading.current_thread() is not threading.main_thread():
-        raise RuntimeError(
-            "A bluesky QtAwareCallback was instantiated from a background "
-            "thread before the bluesky qt 'teleporter' was created. "
-            "To avoid this issue, "
-            "call bluesky.callbacks.mpl_plotting.initialize_qt_teleporter() "
-            "from the main thread first.")
-
-    def handle_teleport(name, doc, obj):
-        obj(name, doc, escape=True)
-
-    class Teleporter(QtCore.QObject):
-        name_doc_escape = QtCore.Signal(str, dict, object)
-
-    t = Teleporter()
-    t.name_doc_escape.connect(handle_teleport)
-    return t
-
-
-class QtAwareCallback(CallbackBase):
-    def __init__(self, *args, use_teleporter=None, **kwargs):
-        if use_teleporter is None:
-            import matplotlib
-            use_teleporter = 'qt' in matplotlib.get_backend().lower()
-        if use_teleporter:
-            self.__teleporter = _get_teleporter()
-        else:
-            self.__teleporter = None
-        super().__init__(*args, **kwargs)
-
-    def __call__(self, name, doc, *, escape=False):
-        if not escape and self.__teleporter is not None:
-            self.__teleporter.name_doc_escape.emit(name, doc, self)
-        else:
-            return CallbackBase.__call__(self, name, doc)
-
-
-
[docs]@make_class_safe(logger=logger) -class LivePlot(QtAwareCallback): - """ - Build a function that updates a plot from a stream of Events. - - Note: If your figure blocks the main thread when you are trying to - scan with this callback, call `plt.ion()` in your IPython session. - - Parameters - ---------- - y : str - the name of a data field in an Event - x : str, optional - the name of a data field in an Event, or 'seq_num' or 'time' - If None, use the Event's sequence number. - Special case: If the Event's data includes a key named 'seq_num' or - 'time', that takes precedence over the standard 'seq_num' and 'time' - recorded in every Event. - legend_keys : list, optional - The list of keys to extract from the RunStart document and format - in the legend of the plot. The legend will always show the - scan_id followed by a colon ("1: "). Each - xlim : tuple, optional - passed to Axes.set_xlim - ylim : tuple, optional - passed to Axes.set_ylim - ax : Axes, optional - matplotib Axes; if none specified, new figure and axes are made. - fig : Figure, optional - deprecated: use ax instead - epoch : {'run', 'unix'}, optional - If 'run' t=0 is the time recorded in the RunStart document. If 'unix', - t=0 is 1 Jan 1970 ("the UNIX epoch"). Default is 'run'. - All additional keyword arguments are passed through to ``Axes.plot``. - - Examples - -------- - >>> my_plotter = LivePlot('det', 'motor', legend_keys=['sample']) - >>> RE(my_scan, my_plotter) - """ - def __init__(self, y, x=None, *, legend_keys=None, xlim=None, ylim=None, - ax=None, fig=None, epoch='run', **kwargs): - super().__init__(use_teleporter=kwargs.pop('use_teleporter', None)) - self.__setup_lock = threading.Lock() - self.__setup_event = threading.Event() - - def setup(): - # Run this code in start() so that it runs on the correct thread. - nonlocal y, x, legend_keys, xlim, ylim, ax, fig, epoch, kwargs - import matplotlib.pyplot as plt - with self.__setup_lock: - if self.__setup_event.is_set(): - return - self.__setup_event.set() - if fig is not None: - if ax is not None: - raise ValueError("Values were given for both `fig` and `ax`. " - "Only one can be used; prefer ax.") - warnings.warn("The `fig` keyword arugment of LivePlot is " - "deprecated and will be removed in the future. " - "Instead, use the new keyword argument `ax` to " - "provide specific Axes to plot on.") - ax = fig.gca() - if ax is None: - fig, ax = plt.subplots() - self.ax = ax - - if legend_keys is None: - legend_keys = [] - self.legend_keys = ['scan_id'] + legend_keys - if x is not None: - self.x, *others = get_obj_fields([x]) - else: - self.x = 'seq_num' - self.y, *others = get_obj_fields([y]) - self.ax.set_ylabel(y) - self.ax.set_xlabel(x or 'sequence #') - if xlim is not None: - self.ax.set_xlim(*xlim) - if ylim is not None: - self.ax.set_ylim(*ylim) - self.ax.margins(.1) - self.kwargs = kwargs - self.lines = [] - self.legend = None - self.legend_title = " :: ".join([name for name in self.legend_keys]) - self._epoch_offset = None # used if x == 'time' - self._epoch = epoch - - self.__setup = setup - - def start(self, doc): - self.__setup() - # The doc is not used; we just use the signal that a new run began. - self._epoch_offset = doc['time'] # used if self.x == 'time' - self.x_data, self.y_data = [], [] - label = " :: ".join( - [str(doc.get(name, name)) for name in self.legend_keys]) - kwargs = ChainMap(self.kwargs, {'label': label}) - self.current_line, = self.ax.plot([], [], **kwargs) - self.lines.append(self.current_line) - legend = self.ax.legend(loc=0, title=self.legend_title) - try: - # matplotlib v3.x - self.legend = legend.set_draggable(True) - except AttributeError: - # matplotlib v2.x (warns in 3.x) - self.legend = legend.draggable(True) - super().start(doc) - - def event(self, doc): - "Unpack data from the event and call self.update()." - # This outer try/except block is needed because multiple event - # streams will be emitted by the RunEngine and not all event - # streams will have the keys we want. - try: - # This inner try/except block handles seq_num and time, which could - # be keys in the data or accessing the standard entries in every - # event. - try: - new_x = doc['data'][self.x] - except KeyError: - if self.x in ('time', 'seq_num'): - new_x = doc[self.x] - else: - raise - new_y = doc['data'][self.y] - except KeyError: - # wrong event stream, skip it - return - - # Special-case 'time' to plot against against experiment epoch, not - # UNIX epoch. - if self.x == 'time' and self._epoch == 'run': - new_x -= self._epoch_offset - - self.update_caches(new_x, new_y) - self.update_plot() - super().event(doc) - - def update_caches(self, x, y): - self.y_data.append(y) - self.x_data.append(x) - - def update_plot(self): - self.current_line.set_data(self.x_data, self.y_data) - # Rescale and redraw. - self.ax.relim(visible_only=True) - self.ax.autoscale_view(tight=True) - self.ax.figure.canvas.draw_idle() - - def stop(self, doc): - if not self.x_data: - print('LivePlot did not get any data that corresponds to the ' - 'x axis. {}'.format(self.x)) - if not self.y_data: - print('LivePlot did not get any data that corresponds to the ' - 'y axis. {}'.format(self.y)) - if len(self.y_data) != len(self.x_data): - print('LivePlot has a different number of elements for x ({}) and' - 'y ({})'.format(len(self.x_data), len(self.y_data))) - super().stop(doc)
- - -
[docs]@make_class_safe(logger=logger) -class LiveScatter(QtAwareCallback): - """Plot scattered 2D data in a "heat map". - - Alternatively, if the data is placed on a regular grid, you can use - :func:`bluesky.callbacks.mpl_plotting.LiveGrid`. - - This simply wraps around a `PathCollection` as generated by scatter. - - Parameters - ---------- - x, y : str - The fields to use for the x and y data - - I : str - The field to use for the color of the markers - - xlim, ylim, clim : tuple, optional - The x, y and color limits respectively - - cmap : str or colormap, optional - The color map to use - - ax : Axes, optional - matplotib Axes; if none specified, new figure and axes are made. - - All additional keyword arguments are passed through to ``Axes.scatter``. - - See Also - -------- - :class:`bluesky.callbacks.mpl_plotting.LiveGrid`. - """ - def __init__(self, x, y, I, *, xlim=None, ylim=None, # noqa: E741 - clim=None, cmap='viridis', ax=None, **kwargs): - super().__init__(use_teleporter=kwargs.pop('use_teleporter', None)) - self.__setup_lock = threading.Lock() - self.__setup_event = threading.Event() - - def setup(): - # Run this code in start() so that it runs on the correct thread. - nonlocal x, y, I, xlim, ylim, clim, cmap, ax, kwargs # noqa: E741 - with self.__setup_lock: - if self.__setup_event.is_set(): - return - self.__setup_event.set() - import matplotlib.pyplot as plt - import matplotlib.colors as mcolors - if ax is None: - fig, ax = plt.subplots() - fig.show() - ax.cla() - self.x = x - self.y = y - self.I = I # noqa: E741 - ax.set_xlabel(x) - ax.set_ylabel(y) - ax.set_aspect('equal') - self._sc = [] - self.ax = ax - ax.margins(.1) - self._xdata, self._ydata, self._Idata = [], [], [] - self._norm = mcolors.Normalize() - self._minx, self._maxx, self._miny, self._maxy = (None,)*4 - - self.xlim = xlim - self.ylim = ylim - if xlim is not None: - ax.set_xlim(xlim) - if ylim is not None: - ax.set_ylim(ylim) - if clim is not None: - self._norm.vmin, self._norm.vmax = clim - self.clim = clim - self.cmap = cmap - self.kwargs = kwargs - self.kwargs.setdefault('edgecolor', 'face') - self.kwargs.setdefault('s', 50) - - self.__setup = setup - - def start(self, doc): - self.__setup() - self._xdata.clear() - self._ydata.clear() - self._Idata.clear() - sc = self.ax.scatter(self._xdata, self._ydata, c=self._Idata, - norm=self._norm, cmap=self.cmap, **self.kwargs) - self._sc.append(sc) - self.sc = sc - cb = self.ax.figure.colorbar(sc, ax=self.ax) - cb.set_label(self.I) - super().start(doc) - - def event(self, doc): - x = doc['data'][self.x] - y = doc['data'][self.y] - I = doc['data'][self.I] # noqa: E741 - self.update(x, y, I) - super().event(doc) - - def update(self, x, y, I): # noqa: E741 - # if one is None all are - if self._minx is None: - self._minx = x - self._maxx = x - self._miny = y - self._maxy = y - - self._xdata.append(x) - self._ydata.append(y) - self._Idata.append(I) - offsets = np.vstack([self._xdata, self._ydata]).T - self.sc.set_offsets(offsets) - self.sc.set_array(np.asarray(self._Idata)) - - if self.xlim is None: - minx, maxx = np.minimum(x, self._minx), np.maximum(x, self._maxx) - self.ax.set_xlim(minx, maxx) - - if self.ylim is None: - miny, maxy = np.minimum(y, self._miny), np.maximum(y, self._maxy) - self.ax.set_ylim(miny, maxy) - - if self.clim is None: - clim = np.nanmin(self._Idata), np.nanmax(self._Idata) - self.sc.set_clim(*clim) - self.ax.figure.canvas.draw_idle()
- - -@make_class_safe(logger=logger) -class LiveMesh(LiveScatter): - __doc__ = LiveScatter.__doc__ - - def __init__(self, *args, **kwargs): - warnings.warn("LiveMesh has been renamed to LiveScatter. The name " - "LiveMesh will eventually be removed. Use LiveScatter.") - super().__init__(*args, **kwargs) - - -
[docs]@make_class_safe(logger=logger) -class LiveGrid(QtAwareCallback): - """Plot gridded 2D data in a "heat map". - - This assumes that readings are placed on a regular grid and can be placed - into an image by sequence number. The seq_num is used to determine which - pixel to fill in. - - For non-gridded data with arbitrary placement, use - :func:`bluesky.callbacks.mpl_plotting.LiveScatter`. - - This simply wraps around a `AxesImage`. - - Parameters - ---------- - raster_shape : tuple - The (row, col) shape of the raster - - I : str - The field to use for the color of the markers - - clim : tuple, optional - The color limits - - cmap : str or colormap, optional - The color map to use - - xlabel, ylabel : str, optional - Labels for the x and y axis - - extent : scalars (left, right, bottom, top), optional - Passed through to :meth:`matplotlib.axes.Axes.imshow` - - aspect : str or float, optional - Passed through to :meth:`matplotlib.axes.Axes.imshow` - - ax : Axes, optional - matplotib Axes; if none specified, new figure and axes are made. - - x_positive: string, optional - Defines the positive direction of the x axis, takes the values 'right' - (default) or 'left'. - - y_positive: string, optional - Defines the positive direction of the y axis, takes the values 'up' - (default) or 'down'. - - See Also - -------- - :class:`bluesky.callbacks.mpl_plotting.LiveScatter`. - """ - def __init__(self, raster_shape, I, *, # noqa: E741 - clim=None, cmap='viridis', - xlabel='x', ylabel='y', extent=None, aspect='equal', - ax=None, x_positive='right', y_positive='up', **kwargs): - super().__init__(**kwargs) - self.__setup_lock = threading.Lock() - self.__setup_event = threading.Event() - - def setup(): - # Run this code in start() so that it runs on the correct thread. - nonlocal raster_shape, I, clim, cmap, xlabel, ylabel, extent # noqa: E741 - nonlocal aspect, ax, x_positive, y_positive, kwargs - with self.__setup_lock: - if self.__setup_event.is_set(): - return - self.__setup_event.set() - import matplotlib.pyplot as plt - import matplotlib.colors as mcolors - if ax is None: - fig, ax = plt.subplots() - ax.cla() - self.I = I # noqa: E741 - ax.set_xlabel(xlabel) - ax.set_ylabel(ylabel) - ax.set_aspect(aspect) - self.ax = ax - self._Idata = np.ones(raster_shape) * np.nan - self._norm = mcolors.Normalize() - if clim is not None: - self._norm.vmin, self._norm.vmax = clim - self.clim = clim - self.cmap = cmap - self.raster_shape = raster_shape - self.im = None - self.extent = extent - self.aspect = aspect - self.x_positive = x_positive - self.y_positive = y_positive - - self.__setup = setup - - def start(self, doc): - self.__setup() - if self.im is not None: - raise RuntimeError("Can not re-use LiveGrid") - self._Idata = np.ones(self.raster_shape) * np.nan - # The user can control origin by specific 'extent'. - extent = self.extent - # origin must be 'lower' for the plot to fill in correctly - # (the first voxel filled must be closest to what mpl thinks - # is the 'lower left' of the image) - im = self.ax.imshow(self._Idata, norm=self._norm, - cmap=self.cmap, interpolation='none', - extent=extent, aspect=self.aspect, - origin='lower') - - # make sure the 'positive direction' of the axes matches what - # is defined in axes_positive - xmin, xmax = self.ax.get_xlim() - if ((xmin > xmax and self.x_positive == 'right') or - (xmax > xmin and self.x_positive == 'left')): - self.ax.set_xlim(xmax, xmin) - elif ((xmax >= xmin and self.x_positive == 'right') or - (xmin >= xmax and self.x_positive == 'left')): - self.ax.set_xlim(xmin, xmax) - else: - raise ValueError('x_positive must be either "right" or "left"') - - ymin, ymax = self.ax.get_ylim() - if ((ymin > ymax and self.y_positive == 'up') or - (ymax > ymin and self.y_positive == 'down')): - self.ax.set_ylim(ymax, ymin) - elif ((ymax >= ymin and self.y_positive == 'up') or - (ymin >= ymax and self.y_positive == 'down')): - self.ax.set_ylim(ymin, ymax) - else: - raise ValueError('y_positive must be either "up" or "down"') - - self.im = im - self.ax.set_title('scan {uid} [{sid}]'.format(sid=doc['scan_id'], - uid=doc['uid'][:6])) - self.snaking = doc.get('snaking', (False, False)) - - cb = self.ax.figure.colorbar(im, ax=self.ax) - cb.set_label(self.I) - super().start(doc) - - def event(self, doc): - if self.I not in doc['data']: - return - - seq_num = doc['seq_num'] - 1 - pos = list(np.unravel_index(seq_num, self.raster_shape)) - if self.snaking[1] and (pos[0] % 2): - pos[1] = self.raster_shape[1] - pos[1] - 1 - pos = tuple(pos) - I = doc['data'][self.I] # noqa: E741 - self.update(pos, I) - super().event(doc) - - def update(self, pos, I): # noqa: E741 - self._Idata[pos] = I - if self.clim is None: - self.im.set_clim(np.nanmin(self._Idata), np.nanmax(self._Idata)) - - self.im.set_array(self._Idata) - self.ax.figure.canvas.draw_idle()
- - -@make_class_safe(logger=logger) -class LiveRaster(LiveGrid): - __doc__ = LiveGrid.__doc__ - - def __init__(self, *args, **kwargs): - warnings.warn("LiveRaster has been renamed to LiveGrid. The name " - "LiveRaster will eventually be removed. Use LiveGrid.") - super().__init__(*args, **kwargs) - - -
[docs]@make_class_safe(logger=logger) -class LiveFitPlot(LivePlot): - """ - Add a plot to an instance of LiveFit. - - Note: If your figure blocks the main thread when you are trying to - scan with this callback, call `plt.ion()` in your IPython session. - - Parameters - ---------- - livefit : LiveFit - an instance of ``LiveFit`` - num_points : int, optional - number of points to sample when evaluating the model; default 100 - legend_keys : list, optional - The list of keys to extract from the RunStart document and format - in the legend of the plot. The legend will always show the - scan_id followed by a colon ("1: "). Each - xlim : tuple, optional - passed to Axes.set_xlim - ylim : tuple, optional - passed to Axes.set_ylim - ax : Axes, optional - matplotib Axes; if none specified, new figure and axes are made. - All additional keyword arguments are passed through to ``Axes.plot``. - """ - def __init__(self, livefit, *, num_points=100, legend_keys=None, xlim=None, - ylim=None, ax=None, **kwargs): - if len(livefit.independent_vars) != 1: - raise NotImplementedError("LiveFitPlot supports models with one " - "independent variable only.") - self.__x_key, = livefit.independent_vars.keys() # this never changes - x, = livefit.independent_vars.values() # this may change - super().__init__(livefit.y, x, legend_keys=legend_keys, - xlim=xlim, ylim=xlim, ax=ax, **kwargs) - self.num_points = num_points - self._livefit = livefit - self._xlim = xlim - self._has_been_run = False - - @property - def livefit(self): - return self._livefit - - def start(self, doc): - super().start(doc) - self.livefit.start(doc) - self.x, = self.livefit.independent_vars.keys() # in case it changed - if self._has_been_run: - label = '_nolegend_' - else: - label = 'init guess' - self._has_been_run = True - self.init_guess_line, = self.ax.plot([], [], color='grey', label=label) - self.lines.append(self.init_guess_line) - # Put fit above other lines (default 2) but below text (default 3). - [line.set_zorder(2.5) for line in self.lines] - - def event(self, doc): - self.livefit.event(doc) - if self.livefit.result is not None: - # Evaluate the model function at equally-spaced points. - # To determine the domain of x, use xlim if availabe. Otherwise, - # use the range of x points measured up to this point. - if self._xlim is None: - x_data = self.livefit.independent_vars_data[self.__x_key] - xmin, xmax = np.min(x_data), np.max(x_data) - else: - xmin, xmax = self._xlim - x_points = np.linspace(xmin, xmax, self.num_points) - kwargs = {self.__x_key: x_points} - kwargs.update(self.livefit.result.values) - self.y_data = self.livefit.result.model.eval(**kwargs) - self.x_data = x_points - # update kwargs to inital guess - kwargs.update(self.livefit.result.init_values) - self.y_guess = self.livefit.result.model.eval(**kwargs) - self.update_plot() - # Intentionally override LivePlot.event. Do not call super(). - - def update_plot(self): - self.current_line.set_data(self.x_data, self.y_data) - self.init_guess_line.set_data(self.x_data, self.y_guess) - # Rescale and redraw. - self.ax.relim(visible_only=True) - self.ax.autoscale_view(tight=True) - self.ax.figure.canvas.draw_idle() - - def descriptor(self, doc): - self.livefit.descriptor(doc) - super().descriptor(doc) - - def stop(self, doc): - self.livefit.stop(doc)
- # Intentionally override LivePlot.stop. Do not call super(). - - -
[docs]def plot_peak_stats(peak_stats, ax=None): - """ - Plot data and various peak statistics. - - Parameters - ---------- - peak_stats : PeakStats - ax : matplotlib.Axes, optional - - Returns - ------- - arts : dict - dictionary of matplotlib Artist objects, for further styling - - """ - import matplotlib.pyplot as plt - arts = {} - ps = peak_stats # for brevity - if ax is None: - fig, ax = plt.subplots() - ax.margins(.1) - # Plot points, vertical lines, and a legend. Collect Artist objs to return. - points, = ax.plot(ps.x_data, ps.y_data, 'o') - vlines = [] - styles = iter(cycler('color', 'krgbm')) - for style, attr in zip(styles, ['cen', 'com']): - print(style, attr) - val = getattr(ps, attr) - if val is None: - continue - vlines.append(ax.axvline(val, label=attr, **style)) - - for style, attr in zip(styles, ['max', 'min']): - print(style, attr) - val = getattr(ps, attr) - if val is None: - continue - vlines.append(ax.axvline(val[0], label=attr, lw=3, **style)) - vlines.append(ax.axhline(val[1], lw=3, **style)) - - if ps.lin_bkg: - lb = ps.lin_bkg - ln, = ax.plot(ps.x_data, ps.x_data*lb['m'] + lb['b'], - ls='--', lw=2, color='k') - arts['bkg'] = ln - - legend = ax.legend(loc='best') - arts.update({'points': points, 'vlines': vlines, 'legend': legend}) - return arts
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/olog.html b/bluesky/_modules/bluesky/callbacks/olog.html deleted file mode 100644 index 1bfcf7925d..0000000000 --- a/bluesky/_modules/bluesky/callbacks/olog.html +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - - - - - bluesky.callbacks.olog — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.olog
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.olog

-from io import StringIO
-from pprint import pformat
-import logging
-from . import CallbackBase
-from collections import defaultdict
-
-logger = logging.getLogger(__name__)
-
-TEMPLATES = {}
-TEMPLATES['long'] = """
-{{- start.plan_name }} ['{{ start.uid[:6] }}'] (scan num: {{ start.scan_id }})
-
-Scan Plan
----------
-{{ start.plan_name }}
-{% if 'plan_args' in start %}
-    {%- for k, v in start.plan_args | dictsort %}
-        {{ k }}: {{ v }}
-    {%-  endfor %}
-{% endif %}
-
-{% if 'signature' in start -%}
-Call:
-    {{ start.signature }}
-{% endif %}
-Metadata
---------
-{% for k, v in start.items() -%}
-{%- if k not in ['plan_name', 'plan_args'] -%}{{ k }} : {{ v }}
-{% endif -%}
-{%- endfor -%}"""
-
-TEMPLATES['desc'] = """
-{{- start.plan_name }} ['{{ start.uid[:6] }}'] (scan num: {{ start.scan_id }})"""
-
-TEMPLATES['call'] = """RE({{ start.plan_name }}(
-{%- for k, v in start.plan_args.items() %}{%- if not loop.first %}   {% endif %}{{ k }}={{ v }}
-{%- if not loop.last %},
-{% endif %}{% endfor %}))
-"""
-
-
-
[docs]def logbook_cb_factory(logbook_func, desc_template=None, long_template=None, - desc_dispatch=None, long_dispatch=None): - """Create a logbook run_start callback - - The returned function is suitable for registering as - a 'start' callback on the the BlueSky run engine. - - Parameters - ---------- - logbook_func : callable - The required signature should match the API ``SimpleOlogClient.log``. - It is: - - .. code-block:: python - - logbook_func(text=None, logbooks=None, tags=None, - properties=None, attachments=None, verify=True, - ensure=False) - - desc_template : str, optional - A jinja2 template to be used for the description line in olog. This is - the default used if the plan_name does not map to a more specific one. - - long_template : str, optional - A jinja2 template to be used for the attachment in olog. This is - the default used if the plan_name does not map to a more specific one. - - desc_dispatch, long_dispatch : mapping, optional - Mappings between 'plan_name' to jinja2 templates to use for the - description and attachments respectively. - """ - import jinja2 - env = jinja2.Environment() - if long_template is None: - long_template = TEMPLATES['long'] - if desc_template is None: - desc_template = TEMPLATES['desc'] - - if desc_dispatch is None: - desc_dispatch = {} - if long_dispatch is None: - long_dispatch = {} - - # It seems that the olog only has one text field, which it calls - # `text` on the python side and 'description' on the olog side. - # There are some CSS applications that try to shove the entire - # thing into a single line. We work around this by doing two - # strings, a long one which will get put in a as an attachment - # and a short one to go in as the 'text' which will be used as the - # description - long_msg = env.from_string(long_template) - desc_msg = env.from_string(desc_template) - - desc_dispatch = defaultdict(lambda: desc_msg, - {k: env.from_string(v) - for k, v in desc_dispatch.items()}) - long_dispatch = defaultdict(lambda: long_msg, - {k: env.from_string(v) - for k, v in long_dispatch.items()}) - - def lbcb(name, doc): - # This only applies to 'start' Documents. - if name != 'start': - return - plan_name = doc.get('plan_name', '') - body = long_dispatch[plan_name] - desc = desc_dispatch[plan_name] - atch = StringIO(body.render(start=doc)) - # monkey-patch a 'name' attribute onto StringIO - atch.name = 'long_description.txt' - desc = desc.render(start=doc) - logbook_func(text=desc, attachments=[atch], ensure=True) - return lbcb
- - -def call_str(start, call_template=None): - """Given a start document generate an evalable call scring - - The default template assumes that `plan_args` and `plan_name` - are at the top level of the document. - - Parameter - --------- - start : dict - A document which follows the runstart schema - - call_template : str, optional - A jinja2 template rendered with `cr.render(start=start)` - - If not provided defaults to `CALL_TEMPLATE` - """ - import jinja2 - env = jinja2.Environment() - if call_template is None: - call_template = TEMPLATES['call'] - call_renderer = env.from_string(call_template) - return call_renderer.render(start=start) - - -class OlogCallback(CallbackBase): - """Example callback to customize the logbook. - - This callback publishes the most recent IPython command (which of course - is not guaranteed to be the one that initiated the run in question) and - the full RunStart Document. - - Example - ------- - # add this callback to the run engine - >>> gs.RE.subscribe(OlogCallback(), 'start') - # turn off the default logger - >>> gs.RE.logbook = None - """ - def __init__(self, logbook): - self.logbook = logbook - from pyOlog import SimpleOlogClient - self.client = SimpleOlogClient() - # Check at init time we are in an IPython session. - from IPython import get_ipython # noqa: F401 - - def start(self, doc): - from IPython import get_ipython - commands = list(get_ipython().history_manager.get_range()) - document_content = ('%s: %s\n\n' - 'RunStart Document\n' - '-----------------\n' - '%s' % (doc['scan_id'], - commands[-1][2], - pformat(doc))) - olog_status = self.client.log(document_content, logbooks=self.logbook) - logger.debug('client.log returned %s' % olog_status) - super().start(doc) -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/stream.html b/bluesky/_modules/bluesky/callbacks/stream.html deleted file mode 100644 index a7de969581..0000000000 --- a/bluesky/_modules/bluesky/callbacks/stream.html +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - - - - - bluesky.callbacks.stream — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.stream
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.stream

-import time as ttime
-from collections.abc import Iterable
-from collections import ChainMap
-
-import numpy as np
-from event_model import DocumentNames, schema_validators
-
-from .core import CallbackBase
-from ..run_engine import Dispatcher
-from ..utils import new_uid
-
-
-
[docs]class LiveDispatcher(CallbackBase): - """ - A secondary event stream of processed data - - The LiveDipatcher base implementation does not change any of the data - emitted, this task is left to sub-classes, but instead handles - reimplementing a secondary event stream that fits the same schema demanded - by the RunEngine itself. In order to reduce the work done by these - processed data pipelines, the LiveDispatcher handles the nitty-gritty - details of formatting the event documents. This includes creating new uids, - numbering events and creating descriptors. - - The LiveDispatcher can be subscribed to using the same syntax as the - RunEngine, effectively creating a small chain of callbacks - - .. code:: - - # Create our dispatcher - ld = LiveDispatcher() - # Subscribe it to receive events from the RunEgine - RE.subscribe(ld) - # Subscribe any callbacks we desire to second stream - ld.subscribe(LivePlot('det', x='motor')) - """ - def __init__(self): - # Public dispatcher for callbacks - self.dispatcher = Dispatcher() - # Local caches for internal use - self.seq_count = 0 # Maintain our own sequence count for this stream - self.raw_descriptors = dict() # Store raw descriptors for use later - self._stream_start_uid = None # Generated start doc uid - self._descriptors = dict() # Dictionary of sent descriptors - -
[docs] def start(self, doc, _md=None): - """Receive a raw start document, re-emit it for the modified stream""" - self._stream_start_uid = new_uid() - _md = _md or dict() - # Create a new start document with a new uid, start time, and the uid - # of the original start document. Preserve the rest of the metadata - # that we retrieved from the start document - md = ChainMap({'uid': self._stream_start_uid, - 'original_run_uid': doc['uid'], - 'time': ttime.time()}, - _md, doc) - # Dispatch the start document for anyone subscribed to our Dispatcher - self.emit(DocumentNames.start, dict(md)) - super().start(doc)
- -
[docs] def descriptor(self, doc): - """Store a descriptor""" - self.raw_descriptors[doc['uid']] = doc - super().descriptor(doc)
- -
[docs] def event(self, doc, **kwargs): - """ - Receive an event document from the raw stream. - - This should be reimplemented by a subclass. - - Parameters - ---------- - doc : event - - kwargs: - All keyword arguments are passed to :meth:`.process_event` - """ - self.process_event(doc, **kwargs) - return super().event(doc)
- -
[docs] def process_event(self, doc, stream_name='primary', - id_args=None, config=None): - """ - Process a modified event document then emit it for the modified stream - - This will pass an Event document to the dispatcher. If we have received - a new event descriptor from the original stream, or we have recieved a - new set of `id_args` or `descriptor_id` , a new descriptor document is - first issued and passed through to the dispatcher. When issuing a new - event, the new descriptor is given a new source field. - - Parameters - ---------- - doc : event - - stream_name : str, optional - String identifier for a particular stream - - id_args : tuple, optional - Additional tuple of hashable objects to identify the stream - - config: dict, optional - Additional configuration information to be included in the event - descriptor - - Notes - ----- - Any callback subscribed to the `Dispatcher` will receive these event - streams. If nothing is subscribed, these documents will not go - anywhere. - """ - id_args = id_args or (doc['descriptor'],) - config = config or dict() - # Determine the descriptor id - desc_id = frozenset((tuple(doc['data'].keys()), stream_name, id_args)) - # If we haven't described this configuration - # Send a new document to our subscribers - if (stream_name not in self._descriptors or - desc_id not in self._descriptors[stream_name]): - # Create a new description document for the output of the stream - data_keys = dict() - # Parse the event document creating a new description. If the key - # existed in the original source description, just assume that it - # is the same type, units and shape. Otherwise do some - # investigation - raw_desc = self.raw_descriptors.get(doc['descriptor'], {}) - for key, val in doc['data'].items(): - # Described priorly - if key in raw_desc['data_keys']: - key_desc = raw_desc['data_keys'][key] - # String key - elif isinstance(val, str): - key_desc = {'dtype': 'string', - 'shape': []} - # Iterable - elif isinstance(val, Iterable): - key_desc = {'dtype': 'array', - 'shape': np.shape(val)} - # Number - else: - key_desc = {'dtype': 'number', - 'shape': []} - # Modify the source - key_desc['source'] = 'Stream' - # Store in our new descriptor - data_keys[key] = key_desc - # Create our complete description document - desc = ChainMap({'uid': new_uid(), 'time': ttime.time(), - 'run_start': self._stream_start_uid, - 'data_keys': data_keys, 'configuration': config, - 'object_keys': {'stream': - list(data_keys.keys())}}, - raw_desc) - # Store information about our descriptors - desc = dict(desc) - if stream_name not in self._descriptors: - self._descriptors[stream_name] = dict() - self._descriptors[stream_name][desc_id] = desc - # Emit the document to all subscribers - self.emit(DocumentNames.descriptor, desc) - - # Clean the Event document produced by graph network. The data is left - # untouched, but the relevant uids, timestamps, seq_num are modified so - # that this event is not confused with the raw data stream - self.seq_count += 1 - desc_uid = self._descriptors[stream_name][desc_id]['uid'] - current_time = ttime.time() - evt = ChainMap({'uid': new_uid(), 'descriptor': desc_uid, - 'timestamps': dict((key, current_time) - for key in doc['data'].keys()), - 'seq_num': self.seq_count, 'time': current_time}, - doc) - # Emit the event document - self.emit(DocumentNames.event, dict(evt))
- -
[docs] def stop(self, doc, _md=None): - """Receive a raw stop document, re-emit it for the modified stream""" - # Create a new stop document with a new_uid, pointing to the correct - # start document uid, and tally the number of events we have emitted. - # The rest of the stop information is passed on to the next callback - _md = _md or dict() - num_events = dict((stream, len(self._descriptors[stream])) - for stream in self._descriptors.keys()) - md = ChainMap(dict(run_start=self._stream_start_uid, - time=ttime.time(), uid=new_uid(), - num_events=num_events), - doc) - self.emit(DocumentNames.stop, dict(md)) - # Clear the local caches for the run - self.seq_count = 0 - self.raw_descriptors.clear() - self._descriptors.clear() - self._stream_start_uid = None - super().stop(doc)
- -
[docs] def emit(self, name, doc): - """Check the document schema and send to the dispatcher""" - schema_validators[name].validate(doc) - self.dispatcher.process(name, doc)
- -
[docs] def subscribe(self, func, name='all'): - """Convenience function for dispatcher subscription""" - return self.dispatcher.subscribe(func, name)
- -
[docs] def unsubscribe(self, token): - """Convenience function for dispatcher un-subscription""" - self.dispatcher.unsubscribe(token)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/callbacks/zmq.html b/bluesky/_modules/bluesky/callbacks/zmq.html deleted file mode 100644 index 2a67b1ebee..0000000000 --- a/bluesky/_modules/bluesky/callbacks/zmq.html +++ /dev/null @@ -1,519 +0,0 @@ - - - - - - - - - - bluesky.callbacks.zmq — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.callbacks.zmq
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.callbacks.zmq

-import asyncio
-import copy
-import pickle
-import warnings
-
-from ..run_engine import Dispatcher, DocumentNames
-
-
-
[docs]class Publisher: - """ - A callback that publishes documents to a 0MQ proxy. - - Parameters - ---------- - address : string or tuple - Address of a running 0MQ proxy, given either as a string like - ``'127.0.0.1:5567'`` or as a tuple like ``('127.0.0.1', 5567)`` - prefix : bytes, optional - User-defined bytestring used to distinguish between multiple - Publishers. May not contain b' '. - RE : ``bluesky.RunEngine``, optional - DEPRECATED. - RunEngine to which the Publisher will be automatically subscribed - (and, more importantly, unsubscribed when it is closed). - zmq : object, optional - By default, the 'zmq' module is imported and used. Anything else - mocking its interface is accepted. - serializer: function, optional - optional function to serialize data. Default is pickle.dumps - - Examples - -------- - - Publish from a RunEngine to a Proxy running on localhost on port 5567. - - >>> publisher = Publisher('localhost:5567') - >>> RE = RunEngine({}) - >>> RE.subscribe(publisher) - """ - def __init__(self, address, *, prefix=b'', - RE=None, zmq=None, serializer=pickle.dumps): - if RE is not None: - warnings.warn("The RE argument to Publisher is deprecated and " - "will be removed in a future release of bluesky. " - "Update your code to subscribe this Publisher " - "instance to (and, if needed, unsubscribe from) to " - "the RunEngine manually.") - if isinstance(prefix, str): - raise ValueError("prefix must be bytes, not string") - if b' ' in prefix: - raise ValueError("prefix {!r} may not contain b' '".format(prefix)) - if zmq is None: - import zmq - if isinstance(address, str): - address = address.split(':', maxsplit=1) - self.address = (address[0], int(address[1])) - self.RE = RE - url = "tcp://%s:%d" % self.address - self._prefix = bytes(prefix) - self._context = zmq.Context() - self._socket = self._context.socket(zmq.PUB) - self._socket.connect(url) - if RE: - self._subscription_token = RE.subscribe(self) - self._serializer = serializer - - def __call__(self, name, doc): - doc = copy.deepcopy(doc) - message = b' '.join([self._prefix, - name.encode(), - self._serializer(doc)]) - self._socket.send(message) - - def close(self): - if self.RE: - self.RE.unsubscribe(self._subscription_token) - self._context.destroy() # close Socket(s); terminate Context
- - -
[docs]class Proxy: - """ - Start a 0MQ proxy on the local host. - - Parameters - ---------- - in_port : int, optional - Port that RunEngines should broadcast to. If None, a random port is - used. - out_port : int, optional - Port that subscribers should subscribe to. If None, a random port is - used. - zmq : object, optional - By default, the 'zmq' module is imported and used. Anything else - mocking its interface is accepted. - - Attributes - ---------- - in_port : int - Port that RunEngines should broadcast to. - out_port : int - Port that subscribers should subscribe to. - closed : boolean - True if the Proxy has already been started and subsequently - interrupted and is therefore unusable. - - Examples - -------- - - Run on specific ports. - - >>> proxy = Proxy(5567, 5568) - >>> proxy - Proxy(in_port=5567, out_port=5568) - >>> proxy.start() # runs until interrupted - - Run on random ports, and access those ports before starting. - - >>> proxy = Proxy() - >>> proxy - Proxy(in_port=56504, out_port=56505) - >>> proxy.in_port - 56504 - >>> proxy.out_port - 56505 - >>> proxy.start() # runs until interrupted - """ - def __init__(self, in_port=None, out_port=None, *, zmq=None): - if zmq is None: - import zmq - self.zmq = zmq - self.closed = False - try: - context = zmq.Context(1) - # Socket facing clients - frontend = context.socket(zmq.SUB) - if in_port is None: - in_port = frontend.bind_to_random_port("tcp://*") - else: - frontend.bind("tcp://*:%d" % in_port) - - frontend.setsockopt_string(zmq.SUBSCRIBE, "") - - # Socket facing services - backend = context.socket(zmq.PUB) - if out_port is None: - out_port = backend.bind_to_random_port("tcp://*") - else: - backend.bind("tcp://*:%d" % out_port) - except BaseException: - # Clean up whichever components we have defined so far. - try: - frontend.close() - except NameError: - ... - try: - backend.close() - except NameError: - ... - context.term() - raise - else: - self.in_port = in_port - self.out_port = out_port - self._frontend = frontend - self._backend = backend - self._context = context - - def start(self): - if self.closed: - raise RuntimeError("This Proxy has already been started and " - "interrupted. Create a fresh instance with " - "{}".format(repr(self))) - try: - self.zmq.device(self.zmq.FORWARDER, self._frontend, self._backend) - finally: - self.closed = True - self._frontend.close() - self._backend.close() - self._context.term() - - def __repr__(self): - return ("{}(in_port={in_port}, out_port={out_port})" - "".format(type(self).__name__, **vars(self)))
- - -
[docs]class RemoteDispatcher(Dispatcher): - """ - Dispatch documents received over the network from a 0MQ proxy. - - Parameters - ---------- - address : tuple - Address of a running 0MQ proxy, given either as a string like - ``'127.0.0.1:5567'`` or as a tuple like ``('127.0.0.1', 5567)`` - prefix : bytes, optional - User-defined bytestring used to distinguish between multiple - Publishers. If set, messages without this prefix will be ignored. - If unset, no mesages will be ignored. - loop : zmq.asyncio.ZMQEventLoop, optional - zmq : object, optional - By default, the 'zmq' module is imported and used. Anything else - mocking its interface is accepted. - zmq_asyncio : object, optional - By default, the 'zmq.asyncio' module is imported and used. Anything - else mocking its interface is accepted. - deserializer: function, optional - optional function to deserialize data. Default is pickle.loads - - Examples - -------- - - Print all documents generated by remote RunEngines. - - >>> d = RemoteDispatcher(('localhost', 5568)) - >>> d.subscribe(print) - >>> d.start() # runs until interrupted - """ - def __init__(self, address, *, prefix=b'', - loop=None, zmq=None, zmq_asyncio=None, - deserializer=pickle.loads): - if isinstance(prefix, str): - raise ValueError("prefix must be bytes, not string") - if b' ' in prefix: - raise ValueError("prefix {!r} may not contain b' '".format(prefix)) - self._prefix = prefix - if zmq is None: - import zmq - if zmq_asyncio is None: - import zmq.asyncio as zmq_asyncio - if isinstance(address, str): - address = address.split(':', maxsplit=1) - self._deserializer = deserializer - self.address = (address[0], int(address[1])) - - if loop is None: - loop = zmq_asyncio.ZMQEventLoop() - self.loop = loop - asyncio.set_event_loop(self.loop) - self._context = zmq_asyncio.Context() - self._socket = self._context.socket(zmq.SUB) - url = "tcp://%s:%d" % self.address - self._socket.connect(url) - self._socket.setsockopt_string(zmq.SUBSCRIBE, "") - self._task = None - self.closed = False - - super().__init__() - - async def _poll(self): - our_prefix = self._prefix # local var to save an attribute lookup - while True: - message = await self._socket.recv() - prefix, name, doc = message.split(b' ', 2) - name = name.decode() - if (not our_prefix) or prefix == our_prefix: - doc = self._deserializer(doc) - self.loop.call_soon(self.process, DocumentNames[name], doc) - - def start(self): - if self.closed: - raise RuntimeError("This RemoteDispatcher has already been " - "started and interrupted. Create a fresh " - "instance with {}".format(repr(self))) - try: - self._task = self.loop.create_task(self._poll()) - self.loop.run_forever() - except BaseException: - self.stop() - raise - - def stop(self): - if self._task is not None: - self._task.cancel() - self.loop.stop() - self._task = None - self.closed = True
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/log.html b/bluesky/_modules/bluesky/log.html deleted file mode 100644 index cc615fe06e..0000000000 --- a/bluesky/_modules/bluesky/log.html +++ /dev/null @@ -1,500 +0,0 @@ - - - - - - - - - - bluesky.log — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.log
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.log

-# The LogFormatter is adapted light from tornado, which is licensed under
-# Apache 2.0. See other_licenses/ in the repository directory.
-import logging
-import sys
-
-try:
-    import colorama
-    colorama.init()
-except ImportError:
-    colorama = None
-try:
-    import curses
-except ImportError:
-    curses = None
-
-__all__ = ('config_bluesky_logging', 'get_handler',
-           'LogFormatter', 'set_handler')
-
-
-def _stderr_supports_color():
-    try:
-        if hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
-            if curses:
-                curses.setupterm()
-                if curses.tigetnum("colors") > 0:
-                    return True
-            elif colorama:
-                if sys.stderr is getattr(colorama.initialise, 'wrapped_stderr',
-                                         object()):
-                    return True
-    except Exception:
-        # Very broad exception handling because it's always better to
-        # fall back to non-colored logs than to break at startup.
-        pass
-    return False
-
-
-class ComposableLogAdapter(logging.LoggerAdapter):
-    def process(self, msg, kwargs):
-        # The logging.LoggerAdapter siliently ignores `extra` in this usage:
-        # log_adapter.debug(msg, extra={...})
-        # and passes through log_adapater.extra instead. This subclass merges
-        # the extra passed via keyword argument with the extra in the
-        # attribute, giving precedence to the keyword argument.
-        kwargs["extra"] = {**self.extra, **kwargs.get('extra', {})}
-        return msg, kwargs
-
-
-
[docs]class LogFormatter(logging.Formatter): - """Log formatter for bluesky records. - - Adapted from the log formatter used in Tornado. - Key features of this formatter are: - - * Color support when logging to a terminal that supports it. - * Timestamps on every log line. - * Includes extra record attributes (old_state, new_state, msg_command, - doc_name, doc_uid) when present. - - """ - DEFAULT_FORMAT = \ - '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s' - DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S' - DEFAULT_COLORS = { - logging.DEBUG: 4, # Blue - logging.INFO: 2, # Green - logging.WARNING: 3, # Yellow - logging.ERROR: 1, # Red - } - - def __init__(self, fmt=DEFAULT_FORMAT, datefmt=DEFAULT_DATE_FORMAT, - style='%', color=True, colors=DEFAULT_COLORS): - r""" - :arg bool color: Enables color support. - :arg str fmt: Log message format. - It will be applied to the attributes dict of log records. The - text between ``%(color)s`` and ``%(end_color)s`` will be colored - depending on the level if color support is on. - :arg dict colors: color mappings from logging level to terminal color - code - :arg str datefmt: Datetime format. - Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``. - .. versionchanged:: 3.2 - Added ``fmt`` and ``datefmt`` arguments. - """ - super().__init__(datefmt=datefmt) - self._fmt = fmt - - self._colors = {} - if color and _stderr_supports_color(): - if curses is not None: - # The curses module has some str/bytes confusion in - # python3. Until version 3.2.3, most methods return - # bytes, but only accept strings. In addition, we want to - # output these strings with the logging module, which - # works with unicode strings. The explicit calls to - # unicode() below are harmless in python2 but will do the - # right conversion in python 3. - fg_color = (curses.tigetstr("setaf") or - curses.tigetstr("setf") or "") - - for levelno, code in colors.items(): - self._colors[levelno] = str(curses.tparm(fg_color, code), "ascii") - self._normal = str(curses.tigetstr("sgr0"), "ascii") - else: - # If curses is not present (currently we'll only get here for - # colorama on windows), assume hard-coded ANSI color codes. - for levelno, code in colors.items(): - self._colors[levelno] = '\033[2;3%dm' % code - self._normal = '\033[0m' - else: - self._normal = '' - - def format(self, record): - message = [] - message.append(record.getMessage()) - record.message = ' '.join(message) - record.asctime = self.formatTime(record, self.datefmt) - - try: - record.color = self._colors[record.levelno] - record.end_color = self._normal - except KeyError: - record.color = '' - record.end_color = '' - - formatted = self._fmt % record.__dict__ - - if record.exc_info and not record.exc_text: - record.exc_text = self.formatException(record.exc_info) - if record.exc_text: - formatted = '{}\n{}'.format(formatted.rstrip(), record.exc_text) - return formatted.replace("\n", "\n ")
- - -plain_log_format = "[%(levelname)1.1s %(asctime)s.%(msecs)03d %(module)15s:%(lineno)5d] %(message)s" -color_log_format = ("%(color)s[%(levelname)1.1s %(asctime)s.%(msecs)03d " - "%(module)15s:%(lineno)5d]%(end_color)s %(message)s") - - -logger = logging.getLogger('bluesky') -doc_logger = logging.getLogger('bluesky.emit_document') -msg_logger = logging.getLogger('bluesky.RE.msg') -state_logger = logging.getLogger('bluesky.RE.state') -current_handler = None - - -def validate_level(level) -> int: - ''' - Return a int for level comparison - - ''' - if isinstance(level, int): - levelno = level - elif isinstance(level, str): - levelno = logging.getLevelName(level) - - if isinstance(levelno, int): - return levelno - else: - raise ValueError("Your level is illegal, please use one of python logging string") - - -def _set_handler_with_logger(logger_name='bluesky', file=sys.stdout, datefmt='%H:%M:%S', color=True, - level='WARNING'): - if isinstance(file, str): - handler = logging.FileHandler(file) - else: - handler = logging.StreamHandler(file) - levelno = validate_level(level) - handler.setLevel(levelno) - if color: - format = color_log_format - else: - format = plain_log_format - handler.setFormatter( - LogFormatter(format, datefmt=datefmt)) - logging.getLogger(logger_name).addHandler(handler) - if logger.getEffectiveLevel() > levelno: - logger.setLevel(levelno) - - -
[docs]def config_bluesky_logging(file=sys.stdout, datefmt='%H:%M:%S', color=True, level='WARNING'): - """ - Set a new handler on the ``logging.getLogger('bluesky')`` logger. - - If this is called more than once, the handler from the previous invocation - is removed (if still present) and replaced. - - Parameters - ---------- - file : object with ``write`` method or filename string - Default is ``sys.stdout``. - datefmt : string - Date format. Default is ``'%H:%M:%S'``. - color : boolean - Use ANSI color codes. True by default. - level : str or int - Python logging level, given as string or corresponding integer. - Default is 'WARNING'. - - Returns - ------- - handler : logging.Handler - The handler, which has already been added to the 'bluesky' logger. - - Examples - -------- - Log to a file. - - >>> config_bluesky_logging(file='/tmp/what_is_happening.txt') - - Include the date along with the time. (The log messages will always include - microseconds, which are configured separately, not as part of 'datefmt'.) - - >>> config_bluesky_logging(datefmt="%Y-%m-%d %H:%M:%S") - - Turn off ANSI color codes. - - >>> config_bluesky_logging(color=False) - - Increase verbosity: show level INFO or higher. - - >>> config_bluesky_logging(level='INFO') - """ - global current_handler - if isinstance(file, str): - handler = logging.FileHandler(file) - else: - handler = logging.StreamHandler(file) - levelno = validate_level(level) - handler.setLevel(levelno) - if color: - format = color_log_format - else: - format = plain_log_format - handler.setFormatter( - LogFormatter(format, datefmt=datefmt)) - if current_handler in logger.handlers: - logger.removeHandler(current_handler) - logger.addHandler(handler) - current_handler = handler - if logger.getEffectiveLevel() > levelno: - logger.setLevel(levelno) - return handler
- - -set_handler = config_bluesky_logging # for back-compat - - -
[docs]def get_handler(): - """ - Return the handler configured by the most recent call to :func:`config_bluesky_logging`. - - If :func:`config_bluesky_logging` has not yet been called, this returns ``None``. - """ - return current_handler
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/plan_stubs.html b/bluesky/_modules/bluesky/plan_stubs.html deleted file mode 100644 index a7d3290509..0000000000 --- a/bluesky/_modules/bluesky/plan_stubs.html +++ /dev/null @@ -1,1426 +0,0 @@ - - - - - - - - - - bluesky.plan_stubs — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.plan_stubs
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.plan_stubs

-import itertools
-import uuid
-from cycler import cycler
-from . import utils
-import operator
-from functools import reduce
-from collections.abc import Iterable
-import time
-import warnings
-
-try:
-    # cytools is a drop-in replacement for toolz, implemented in Cython
-    from cytools import partition
-except ImportError:
-    from toolz import partition
-
-
-from .utils import (
-    separate_devices,
-    all_safe_rewind,
-    Msg,
-    ensure_generator,
-    short_uid as _short_uid,
-)
-
-
-
[docs]def create(name='primary'): - """ - Bundle future readings into a new Event document. - - Parameters - ---------- - name : string, optional - name given to event stream, used to convenient identification - default is 'primary' - - Yields - ------ - msg : Msg - Msg('create', name=name) - - See Also - -------- - :func:`bluesky.plan_stubs.save` - """ - return (yield Msg('create', name=name))
- - -
[docs]def save(): - """ - Close a bundle of readings and emit a completed Event document. - - Yields - ------- - msg : Msg - Msg('save') - - See Also - -------- - :func:`bluesky.plan_stubs.create` - """ - return (yield Msg('save'))
- - -
[docs]def drop(): - """ - Drop a bundle of readings without emitting a completed Event document. - - Yields - ------ - msg : Msg - Msg('drop') - - See Also - -------- - :func:`bluesky.plan_stubs.save` - :func:`bluesky.plan_stubs.create` - """ - return (yield Msg('drop'))
- - -
[docs]def read(obj): - """ - Take a reading and add it to the current bundle of readings. - - Parameters - ---------- - obj : Device or Signal - - Yields - ------ - msg : Msg - Msg('read', obj) - """ - return (yield Msg('read', obj))
- - -
[docs]def monitor(obj, *, name=None, **kwargs): - """ - Asynchronously monitor for new values and emit Event documents. - - Parameters - ---------- - obj : Signal - args : - passed through to ``obj.subscribe()`` - name : string, optional - name of event stream; default is None - kwargs : - passed through to ``obj.subscribe()`` - - Yields - ------ - msg : Msg - ``Msg('monitor', obj, *args, **kwargs)`` - - See Also - -------- - :func:`bluesky.plan_stubs.unmonitor` - """ - return (yield Msg('monitor', obj, name=name, **kwargs))
- - -
[docs]def unmonitor(obj): - """ - Stop monitoring. - - Parameters - ---------- - obj : Signal - - Yields - ------ - msg : Msg - Msg('unmonitor', obj) - - See Also - -------- - :func:`bluesky.plan_stubs.monitor` - """ - return (yield Msg('unmonitor', obj))
- - -
[docs]def null(): - """ - Yield a no-op Message. (Primarily for debugging and testing.) - - Yields - ------ - msg : Msg - Msg('null') - """ - return (yield Msg('null'))
- - -
[docs]def abs_set(obj, *args, group=None, wait=False, **kwargs): - """ - Set a value. Optionally, wait for it to complete before continuing. - - Parameters - ---------- - obj : Device - group : string (or any hashable object), optional - identifier used by 'wait' - wait : boolean, optional - If True, wait for completion before processing any more messages. - False by default. - args : - passed to obj.set() - kwargs : - passed to obj.set() - - Yields - ------ - msg : Msg - - See Also - -------- - :func:`bluesky.plan_stubs.rel_set` - :func:`bluesky.plan_stubs.wait` - :func:`bluesky.plan_stubs.mv` - """ - if wait and group is None: - group = str(uuid.uuid4()) - ret = yield Msg('set', obj, *args, group=group, **kwargs) - if wait: - yield Msg('wait', None, group=group) - return ret
- - -
[docs]def rel_set(obj, *args, group=None, wait=False, **kwargs): - """ - Set a value relative to current value. Optionally, wait before continuing. - - Parameters - ---------- - obj : Device - group : string (or any hashable object), optional - identifier used by 'wait'; None by default - wait : boolean, optional - If True, wait for completion before processing any more messages. - False by default. - args : - passed to obj.set() - kwargs : - passed to obj.set() - - Yields - ------ - msg : Msg - - See Also - -------- - :func:`bluesky.plan_stubs.abs_set` - :func:`bluesky.plan_stubs.wait` - """ - from .preprocessors import relative_set_wrapper - - return ( - yield from relative_set_wrapper( - abs_set(obj, *args, group=group, wait=wait, **kwargs) - ) - )
- - -
[docs]def mv(*args, group=None, **kwargs): - """ - Move one or more devices to a setpoint. Wait for all to complete. - - If more than one device is specifed, the movements are done in parallel. - - Parameters - ---------- - args : - device1, value1, device2, value2, ... - group : string, optional - Used to mark these as a unit to be waited on. - kwargs : - passed to obj.set() - - Yields - ------ - msg : Msg - - See Also - -------- - :func:`bluesky.plan_stubs.abs_set` - :func:`bluesky.plan_stubs.mvr` - """ - group = group or str(uuid.uuid4()) - status_objects = [] - - cyl = reduce(operator.add, [cycler(obj, [val]) for obj, val in partition(2, args)]) - (step,) = utils.merge_cycler(cyl) - for obj, val in step.items(): - ret = yield Msg('set', obj, val, group=group, **kwargs) - status_objects.append(ret) - yield Msg('wait', None, group=group) - return tuple(status_objects)
- - -mov = mv # synonym - - -
[docs]def mvr(*args, group=None, **kwargs): - """ - Move one or more devices to a relative setpoint. Wait for all to complete. - - If more than one device is specifed, the movements are done in parallel. - - Parameters - ---------- - args : - device1, value1, device2, value2, ... - group : string, optional - Used to mark these as a unit to be waited on. - kwargs : - passed to obj.set() - - Yields - ------ - msg : Msg - - See Also - -------- - :func:`bluesky.plan_stubs.rel_set` - :func:`bluesky.plan_stubs.mv` - """ - objs = [] - for obj, val in partition(2, args): - objs.append(obj) - - from .preprocessors import relative_set_decorator - - @relative_set_decorator(objs) - def inner_mvr(): - return (yield from mv(*args, group=group, **kwargs)) - - return (yield from inner_mvr())
- - -movr = mvr # synonym - - -
[docs]def rd(obj, *, default_value=0): - """Reads a single-value non-triggered object - - This is a helper plan to get the scalar value out of a Device - (such as an EpicsMotor or a single EpicsSignal). - - For devices that have more than one read key the following rules are used: - - - if exactly 1 field is hinted that value is used - - if no fields are hinted and there is exactly 1 value in the - reading that value is used - - if more than one field is hinted an Exception is raised - - if no fields are hinted and there is more than one key in the reading an - Exception is raised - - The devices is not triggered and this plan does not create any Events - - Parameters - ---------- - obj : Device - The device to be read - - default_value : Any - The value to return when not running in a "live" RunEngine. - This come ups when :: - - ret = yield Msg('read', obj) - assert ret is None - - the plan is passed to `list` or some other iterator that - repeatedly sends `None` into the plan to advance the - generator. - - Returns - ------- - val : Any or None - The "single" value of the device - - """ - hints = getattr(obj, 'hints', {}).get("fields", []) - if len(hints) > 1: - msg = ( - f"Your object {obj} ({obj.name}.{getattr(obj, 'dotted_name', '')}) " - f"has {len(hints)} items hinted ({hints}). We do not know how to " - "pick out a single value. Please adjust the hinting by setting the " - "kind of the components of this device or by rd ing one of it's components" - ) - raise ValueError(msg) - elif len(hints) == 0: - hint = None - if hasattr(obj, "read_attrs"): - if len(obj.read_attrs) != 1: - msg = ( - f"Your object {obj} ({obj.name}.{getattr(obj, 'dotted_name', '')}) " - f"and has {len(obj.read_attrs)} read attrs. We do not know how to " - "pick out a single value. Please adjust the hinting/read_attrs by " - "setting the kind of the components of this device or by rd ing one " - "of its components" - ) - - raise ValueError(msg) - # len(hints) == 1 - else: - (hint,) = hints - - ret = yield from read(obj) - - # list-ify mode - if ret is None: - return default_value - - if hint is not None: - return ret[hint]["value"] - - # handle the no hint 1 field case - try: - (data,) = ret.values() - except ValueError as er: - msg = ( - f"Your object {obj} ({obj.name}.{getattr(obj, 'dotted_name', '')}) " - f"and has {len(ret)} read values. We do not know how to pick out a " - "single value. Please adjust the hinting/read_attrs by setting the " - "kind of the components of this device or by rd ing one of its components" - ) - - raise ValueError(msg) from er - else: - return data["value"]
- - -
[docs]def stop(obj): - """ - Stop a device. - - Parameters - ---------- - obj : Device - - Yields - ------ - msg : Msg - """ - return (yield Msg('stop', obj))
- - -
[docs]def trigger(obj, *, group=None, wait=False): - """ - Trigger and acquisition. Optionally, wait for it to complete. - - Parameters - ---------- - obj : Device - group : string (or any hashable object), optional - identifier used by 'wait'; None by default - wait : boolean, optional - If True, wait for completion before processing any more messages. - False by default. - - Yields - ------ - msg : Msg - """ - ret = yield Msg('trigger', obj, group=group) - if wait: - yield Msg('wait', None, group=group) - return ret
- - -
[docs]def sleep(time): - """ - Tell the RunEngine to sleep, while asynchronously doing other processing. - - This is not the same as ``import time; time.sleep()`` because it allows - other actions, like interruptions, to be processed during the sleep. - - Parameters - ---------- - time : float - seconds - - Yields - ------ - msg : Msg - Msg('sleep', None, time) - """ - return (yield Msg('sleep', None, time))
- - -
[docs]def wait(group=None): - """ - Wait for all statuses in a group to report being finished. - - Parameters - ---------- - group : string (or any hashable object), optional - idenified given to `abs_set`, `rel_set`, `trigger`; None by default - - Yields - ------ - msg : Msg - Msg('wait', None, group=group) - """ - return (yield Msg('wait', None, group=group))
- - -_wait = wait # for internal references to avoid collision with 'wait' kwarg - - -
[docs]def checkpoint(): - """ - If interrupted, rewind to this point. - - Yields - ------ - msg : Msg - Msg('checkpoint') - - See Also - -------- - :func:`bluesky.plan_stubs.clear_checkpoint` - """ - return (yield Msg('checkpoint'))
- - -
[docs]def clear_checkpoint(): - """ - Designate that it is not safe to resume. If interrupted or paused, abort. - - Yields - ------ - msg : Msg - Msg('clear_checkpoint') - - See Also - -------- - :func:`bluesky.plan_stubs.checkpoint` - """ - return (yield Msg('clear_checkpoint'))
- - -
[docs]def pause(): - """ - Pause and wait for the user to resume. - - Yields - ------ - msg : Msg - Msg('pause') - - See Also - -------- - :func:`bluesky.plan_stubs.deferred_pause` - :func:`bluesky.plan_stubs.sleep` - """ - return (yield Msg('pause', None, defer=False))
- - -
[docs]def deferred_pause(): - """ - Pause at the next checkpoint. - - Yields - ------ - msg : Msg - Msg('pause', defer=True) - - See Also - -------- - :func:`bluesky.plan_stubs.pause` - :func:`bluesky.plan_stubs.sleep` - """ - return (yield Msg('pause', None, defer=True))
- - -
[docs]def input_plan(prompt=''): - """ - Prompt the user for text input. - - Parameters - ---------- - prompt : str - prompt string, e.g., 'enter user name' or 'enter next position' - - Yields - ------ - msg : Msg - Msg('input', prompt=prompt) - """ - return (yield Msg('input', prompt=prompt))
- - -
[docs]def kickoff(obj, *, group=None, wait=False, **kwargs): - """ - Kickoff a fly-scanning device. - - Parameters - ---------- - obj : fly-able - Device with 'kickoff', 'complete', and 'collect' methods - group : string (or any hashable object), optional - identifier used by 'wait' - wait : boolean, optional - If True, wait for completion before processing any more messages. - False by default. - kwargs - passed through to ``obj.kickoff()`` - - Yields - ------ - msg : Msg - Msg('kickoff', obj) - - See Also - -------- - :func:`bluesky.plan_stubs.complete` - :func:`bluesky.plan_stubs.collect` - :func:`bluesky.plan_stubs.wait` - """ - ret = (yield Msg('kickoff', obj, group=group, **kwargs)) - if wait: - yield from _wait(group=group) - return ret
- - -
[docs]def complete(obj, *, group=None, wait=False, **kwargs): - """ - Tell a flyer, 'stop collecting, whenver you are ready'. - - The flyer returns a status object. Some flyers respond to this - command by stopping collection and returning a finished status - object immedately. Other flyers finish their given course and - finish whenever they finish, irrespective of when this command is - issued. - - Parameters - ---------- - obj : fly-able - Device with 'kickoff', 'complete', and 'collect' methods - group : string (or any hashable object), optional - identifier used by 'wait' - wait : boolean, optional - If True, wait for completion before processing any more messages. - False by default. - kwargs - passed through to ``obj.complete()`` - - Yields - ------ - msg : Msg - a 'complete' Msg and maybe a 'wait' message - - See Also - -------- - :func:`bluesky.plan_stubs.kickoff` - :func:`bluesky.plan_stubs.collect` - :func:`bluesky.plan_stubs.wait` - """ - ret = yield Msg('complete', obj, group=group, **kwargs) - if wait: - yield from _wait(group=group) - return ret
- - -
[docs]def collect(obj, *, stream=False, return_payload=True): - """ - Collect data cached by a fly-scanning device and emit documents. - - Parameters - ---------- - obj : fly-able - Device with 'kickoff', 'complete', and 'collect' methods - stream : boolean, optional - If False (default), emit Event documents in one bulk dump. If True, - emit events one at time. - return_payload: boolean, optional - If True (default), return the collected Events. If False, return None. - Using ``stream=True`` and ``return_payload=False`` together avoids - accumulating the documents in memory: they are emmitted as they are - collected, and they are not accumulated. - - Yields - ------ - msg : Msg - Msg('collect', obj) - - See Also - -------- - :func:`bluesky.plan_stubs.kickoff` - :func:`bluesky.plan_stubs.complete` - :func:`bluesky.plan_stubs.wait` - """ - return (yield Msg('collect', obj, stream=stream, return_payload=return_payload))
- - -
[docs]def configure(obj, *args, **kwargs): - """ - Change Device configuration and emit an updated Event Descriptor document. - - Parameters - ---------- - obj : Device - args - passed through to ``obj.configure()`` - kwargs - passed through to ``obj.configure()`` - - Yields - ------ - msg : Msg - ``Msg('configure', obj, *args, **kwargs)`` - """ - return (yield Msg('configure', obj, *args, **kwargs))
- - -
[docs]def stage(obj): - """ - 'Stage' a device (i.e., prepare it for use, 'arm' it). - - Parameters - ---------- - obj : Device - - Yields - ------ - msg : Msg - Msg('stage', obj) - - See Also - -------- - :func:`bluesky.plan_stubs.unstage` - """ - return (yield Msg('stage', obj))
- - -
[docs]def unstage(obj): - """ - 'Unstage' a device (i.e., put it in standby, 'disarm' it). - - Parameters - ---------- - obj : Device - - Yields - ------ - msg : Msg - Msg('unstage', obj) - - See Also - -------- - :func:`bluesky.plan_stubs.stage` - """ - return (yield Msg('unstage', obj))
- - -
[docs]def subscribe(name, func): - """ - Subscribe the stream of emitted documents. - - Parameters - ---------- - name : {'all', 'start', 'descriptor', 'event', 'stop'} - func : callable - Expected signature: ``f(name, doc)`` where ``name`` is one of the - strings above ('all, 'start', ...) and ``doc`` is a dict - - Yields - ------ - msg : Msg - Msg('subscribe', None, func, name) - - See Also - -------- - :func:`bluesky.plan_stubs.unsubscribe` - """ - return (yield Msg('subscribe', None, func, name))
- - -
[docs]def unsubscribe(token): - """ - Remove a subscription. - - Parameters - ---------- - token : int - token returned by processing a 'subscribe' message - - Yields - ------ - msg : Msg - Msg('unsubscribe', token=token) - - See Also - -------- - :func:`bluesky.plan_stubs.subscribe` - """ - return (yield Msg('unsubscribe', token=token))
- - -
[docs]def install_suspender(suspender): - """ - Install a suspender during a plan. - - Parameters - ---------- - suspender : :class:`bluesky.suspenders.SuspenderBase` - The suspender to install - - Yields - ------ - msg : Msg - Msg('install_suspender', None, suspender) - - See Also - -------- - :func:`bluesky.plan_stubs.remove_suspender` - """ - return (yield Msg('install_suspender', None, suspender))
- - -
[docs]def remove_suspender(suspender): - """ - Remove a suspender during a plan. - - Parameters - ---------- - suspender : :class:`bluesky.suspenders.SuspenderBase` - The suspender to remove - - Yields - ------ - msg : Msg - Msg('remove_suspender', None, suspender) - - See Also - -------- - :func:`bluesky.plan_stubs.install_suspender` - """ - return (yield Msg('remove_suspender', None, suspender))
- - -
[docs]def open_run(md=None): - """ - Mark the beginning of a new 'run'. Emit a RunStart document. - - Parameters - ---------- - md : dict, optional - metadata - - Yields - ------ - msg : Msg - ``Msg('open_run', **md)`` - - See Also - -------- - :func:`bluesky.plans_stubs.close_run` - """ - return (yield Msg('open_run', **(md or {})))
- - -
[docs]def close_run(exit_status=None, reason=None): - """ - Mark the end of the current 'run'. Emit a RunStop document. - - Yields - ------ - msg : Msg - Msg('close_run') - exit_status : {None, 'success', 'abort', 'fail'} - The exit status to report in the Stop document - reason : str, optional - Long-form description of why the run ended - - See Also - -------- - :func:`bluesky.plans_stubs.open_run` - """ - return (yield Msg('close_run', exit_status=exit_status, reason=reason))
- - -
[docs]def wait_for(futures, **kwargs): - """ - Low-level: wait for a list of ``asyncio.Future`` objects to set (complete). - - Parameters - ---------- - futures : collection - collection of asyncio.Future objects - kwargs - passed through to ``asyncio.wait()`` - - Yields - ------ - msg : Msg - ``Msg('wait_for', None, futures, **kwargs)`` - - See Also - -------- - :func:`bluesky.plan_stubs.wait` - """ - return (yield Msg('wait_for', None, futures, **kwargs))
- - -
[docs]def trigger_and_read(devices, name='primary'): - """ - Trigger and read a list of detectors and bundle readings into one Event. - - Parameters - ---------- - devices : iterable - devices to trigger (if they have a trigger method) and then read - name : string, optional - event stream name, a convenient human-friendly identifier; default - name is 'primary' - - Yields - ------ - msg : Msg - messages to 'trigger', 'wait' and 'read' - """ - # If devices is empty, don't emit 'create'/'save' messages. - if not devices: - yield from null() - devices = separate_devices(devices) # remove redundant entries - rewindable = all_safe_rewind(devices) # if devices can be re-triggered - - def inner_trigger_and_read(): - grp = _short_uid('trigger') - no_wait = True - for obj in devices: - if hasattr(obj, 'trigger'): - no_wait = False - yield from trigger(obj, group=grp) - # Skip 'wait' if none of the devices implemented a trigger method. - if not no_wait: - yield from wait(group=grp) - yield from create(name) - ret = {} # collect and return readings to give plan access to them - for obj in devices: - reading = (yield from read(obj)) - if reading is not None: - ret.update(reading) - yield from save() - return ret - from .preprocessors import rewindable_wrapper - return (yield from rewindable_wrapper(inner_trigger_and_read(), - rewindable))
- - -
[docs]def broadcast_msg(command, objs, *args, **kwargs): - """ - Generate many copies of a mesasge, applying it to a list of devices. - - Parameters - ---------- - command : string - devices : iterable - ``*args`` - args for message - ``**kwargs`` - kwargs for message - - Yields - ------ - msg : Msg - """ - return_vals = [] - for o in objs: - ret = yield Msg(command, o, *args, **kwargs) - return_vals.append(ret) - - return return_vals
- - -
[docs]def repeater(n, gen_func, *args, **kwargs): - """ - Generate n chained copies of the messages from gen_func - - Parameters - ---------- - n : int or None - total number of repetitions; if None, infinite - gen_func : callable - returns generator instance - ``*args`` - args for gen_func - ``**kwargs`` - kwargs for gen_func - - Yields - ------ - msg : Msg - - See Also - -------- - :func:`bluesky.plan_stubs.caching_repeater` - """ - it = range - if n is None: - n = 0 - it = itertools.count - - for j in it(n): - yield from gen_func(*args, **kwargs)
- - -
[docs]def caching_repeater(n, plan): - """ - Generate n chained copies of the messages in a plan. - - This is different from ``repeater`` above because it takes in a - generator or iterator, not a function that returns one. - - Parameters - ---------- - n : int or None - total number of repetitions; if None, infinite - plan : iterable - - Yields - ------ - msg : Msg - - See Also - -------- - :func:`bluesky.plan_stubs.repeater` - """ - warnings.warn("The caching_repeater will be removed in a future version " - "of bluesky.", stacklevel=2) - if n is None: - gen = itertools.count(0) - else: - gen = range(n) - - lst_plan = list(plan) - for _ in gen: - yield from (m for m in lst_plan)
- - -
[docs]def one_shot(detectors, take_reading=trigger_and_read): - """Inner loop of a count. - - This is the default function for ``per_shot`` in count plans. - - Parameters - ---------- - detectors : Iterable[OphydObj] - devices to read - - take_reading : plan, optional - function to do the actual acquisition :: - - def take_reading(dets, name='primary'): - yield from ... - - Callable[List[OphydObj], Optional[str]] -> Generator[Msg], optional - - Defaults to `trigger_and_read` - """ - yield Msg('checkpoint') - yield from take_reading(list(detectors))
- - -
[docs]def one_1d_step(detectors, motor, step, take_reading=trigger_and_read): - """ - Inner loop of a 1D step scan - - This is the default function for ``per_step`` param in 1D plans. - - Parameters - ---------- - detectors : iterable - devices to read - motor : Settable - The motor to move - step : Any - Where to move the motor to - take_reading : plan, optional - function to do the actual acquisition :: - - def take_reading(dets, name='primary'): - yield from ... - - Callable[List[OphydObj], Optional[str]] -> Generator[Msg], optional - - Defaults to `trigger_and_read` - """ - def move(): - grp = _short_uid('set') - yield Msg('checkpoint') - yield Msg('set', motor, step, group=grp) - yield Msg('wait', None, group=grp) - - yield from move() - return (yield from take_reading(list(detectors) + [motor]))
- - -
[docs]def move_per_step(step, pos_cache): - """ - Inner loop of an N-dimensional step scan without any readings - - This can be used as a building block for custom ``per_step`` stubs. - - Parameters - ---------- - step : dict - mapping motors to positions in this step - pos_cache : dict - mapping motors to their last-set positions - """ - yield Msg('checkpoint') - grp = _short_uid('set') - for motor, pos in step.items(): - if pos == pos_cache[motor]: - # This step does not move this motor. - continue - yield Msg('set', motor, pos, group=grp) - pos_cache[motor] = pos - yield Msg('wait', None, group=grp)
- - -
[docs]def one_nd_step(detectors, step, pos_cache, take_reading=trigger_and_read): - """ - Inner loop of an N-dimensional step scan - - This is the default function for ``per_step`` param`` in ND plans. - - Parameters - ---------- - detectors : iterable - devices to read - step : dict - mapping motors to positions in this step - pos_cache : dict - mapping motors to their last-set positions - take_reading : plan, optional - function to do the actual acquisition :: - - def take_reading(dets, name='primary'): - yield from ... - - Callable[List[OphydObj], Optional[str]] -> Generator[Msg], optional - - Defaults to `trigger_and_read` - """ - motors = step.keys() - yield from move_per_step(step, pos_cache) - yield from take_reading(list(detectors) + list(motors))
- - -
[docs]def repeat(plan, num=1, delay=None): - """ - Repeat a plan num times with delay and checkpoint between each repeat. - - This is different from ``repeater`` and ``caching_repeater`` in that it - adds ``checkpoint`` and optionally ``sleep`` messages if delay is provided. - This is intended for users who need the structure of ``count`` but do not - want to reimplement the control flow. - - Parameters - ---------- - plan: callable - Callable that returns an iterable of Msg objects - num : integer, optional - number of readings to take; default is 1 - - If None, capture data until canceled - delay : iterable or scalar, optional - time delay between successive readings; default is 0 - - Notes - ----- - If ``delay`` is an iterable, it must have at least ``num - 1`` entries or - the plan will raise a ``ValueError`` during iteration. - """ - # Create finite or infinite counter - if num is None: - iterator = itertools.count() - else: - iterator = range(num) - - # If delay is a scalar, repeat it forever. If it is an iterable, leave it. - if not isinstance(delay, Iterable): - delay = itertools.repeat(delay) - else: - try: - num_delays = len(delay) - except TypeError: - # No way to tell in advance if we have enough delays. - pass - else: - if num - 1 > num_delays: - raise ValueError("num=%r but delays only provides %r " - "entries" % (num, num_delays)) - delay = iter(delay) - - def repeated_plan(): - for i in iterator: - now = time.time() # Intercept the flow in its earliest moment. - yield Msg('checkpoint') - yield from ensure_generator(plan()) - try: - d = next(delay) - except StopIteration: - if i + 1 == num: - break - elif num is None: - break - else: - # num specifies a number of iterations less than delay - raise ValueError("num=%r but delays only provides %r " - "entries" % (num, i)) - if d is not None: - d = d - (time.time() - now) - if d > 0: # Sleep if and only if time is left to do it. - yield Msg('sleep', None, d) - - return (yield from repeated_plan())
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/plans.html b/bluesky/_modules/bluesky/plans.html deleted file mode 100644 index e7374e0678..0000000000 --- a/bluesky/_modules/bluesky/plans.html +++ /dev/null @@ -1,2264 +0,0 @@ - - - - - - - - - - bluesky.plans — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.plans
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.plans

-import sys
-import inspect
-from itertools import chain, zip_longest
-from functools import partial
-import collections
-from collections import defaultdict
-import time
-
-import numpy as np
-try:
-    # cytools is a drop-in replacement for toolz, implemented in Cython
-    from cytools import partition
-except ImportError:
-    from toolz import partition
-
-from . import plan_patterns
-
-from . import utils
-from .utils import Msg
-
-from . import preprocessors as bpp
-from . import plan_stubs as bps
-
-
-
[docs]def count(detectors, num=1, delay=None, *, per_shot=None, md=None): - """ - Take one or more readings from detectors. - - Parameters - ---------- - detectors : list - list of 'readable' objects - num : integer, optional - number of readings to take; default is 1 - - If None, capture data until canceled - delay : iterable or scalar, optional - Time delay in seconds between successive readings; default is 0. - per_shot : callable, optional - hook for customizing action of inner loop (messages per step) - Expected signature :: - - def f(detectors: Iterable[OphydObj]) -> Generator[Msg]: - ... - - md : dict, optional - metadata - - Notes - ----- - If ``delay`` is an iterable, it must have at least ``num - 1`` entries or - the plan will raise a ``ValueError`` during iteration. - """ - if num is None: - num_intervals = None - else: - num_intervals = num - 1 - _md = {'detectors': [det.name for det in detectors], - 'num_points': num, - 'num_intervals': num_intervals, - 'plan_args': {'detectors': list(map(repr, detectors)), 'num': num}, - 'plan_name': 'count', - 'hints': {} - } - _md.update(md or {}) - _md['hints'].setdefault('dimensions', [(('time',), 'primary')]) - - if per_shot is None: - per_shot = bps.one_shot - - @bpp.stage_decorator(detectors) - @bpp.run_decorator(md=_md) - def inner_count(): - return (yield from bps.repeat(partial(per_shot, detectors), - num=num, delay=delay)) - - return (yield from inner_count())
- - -
[docs]def list_scan(detectors, *args, per_step=None, md=None): - """ - Scan over one or more variables in steps simultaneously (inner product). - - Parameters - ---------- - detectors : list - list of 'readable' objects - *args : - For one dimension, ``motor, [point1, point2, ....]``. - In general: - - .. code-block:: python - - motor1, [point1, point2, ...], - motor2, [point1, point2, ...], - ..., - motorN, [point1, point2, ...] - - Motors can be any 'settable' object (motor, temp controller, etc.) - - per_step : callable, optional - hook for customizing action of inner loop (messages per step) - Expected signature: - ``f(detectors, motor, step) -> plan (a generator)`` - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_list_scan` - :func:`bluesky.plans.list_grid_scan` - :func:`bluesky.plans.rel_list_grid_scan` - """ - if len(args) % 2 != 0: - raise ValueError("The list of arguments must contain a list of " - "points for each defined motor") - - md = md or {} # reset md if it is None. - - # set some variables and check that all lists are the same length - lengths = {} - motors = [] - pos_lists = [] - length = None - for motor, pos_list in partition(2, args): - pos_list = list(pos_list) # Ensure list (accepts any finite iterable). - lengths[motor.name] = len(pos_list) - if not length: - length = len(pos_list) - motors.append(motor) - pos_lists.append(pos_list) - length_check = all(elem == list(lengths.values())[0] for elem in - list(lengths.values())) - - if not length_check: - raise ValueError("The lengths of all lists in *args must be the same. " - "However the lengths in args are : " - "{}".format(lengths)) - - md_args = list(chain(*((repr(motor), pos_list) - for motor, pos_list in partition(2, args)))) - motor_names = list(lengths.keys()) - - _md = {'detectors': [det.name for det in detectors], - 'motors': motor_names, - 'num_points': length, - 'num_intervals': length - 1, - 'plan_args': {'detectors': list(map(repr, detectors)), - 'args': md_args, - 'per_step': repr(per_step)}, - 'plan_name': 'list_scan', - 'plan_pattern': 'inner_list_product', - 'plan_pattern_module': plan_patterns.__name__, - 'plan_pattern_args': dict(args=md_args), - 'hints': {}, - } - _md.update(md or {}) - - x_fields = [] - for motor in motors: - x_fields.extend(getattr(motor, 'hints', {}).get('fields', [])) - - default_dimensions = [(x_fields, 'primary')] - - default_hints = {} - if len(x_fields) > 0: - default_hints.update(dimensions=default_dimensions) - - # now add default_hints and override any hints from the original md (if - # exists) - _md['hints'] = default_hints - _md['hints'].update(md.get('hints', {}) or {}) - - full_cycler = plan_patterns.inner_list_product(args) - - return (yield from scan_nd(detectors, full_cycler, per_step=per_step, - md=_md))
- - -
[docs]def rel_list_scan(detectors, *args, per_step=None, md=None): - """ - Scan over one variable in steps relative to current position. - - Parameters - ---------- - detectors : list - list of 'readable' objects - *args : - For one dimension, ``motor, [point1, point2, ....]``. - In general: - - .. code-block:: python - - motor1, [point1, point2, ...], - motor2, [point1, point2, ...], - ..., - motorN, [point1, point2, ...] - - Motors can be any 'settable' object (motor, temp controller, etc.) - point1, point2 etc are relative to the current location. - - motor : object - any 'settable' object (motor, temp controller, etc.) - steps : list - list of positions relative to current position - per_step : callable, optional - hook for customizing action of inner loop (messages per step) - Expected signature: ``f(detectors, motor, step)`` - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.list_scan` - :func:`bluesky.plans.list_grid_scan` - :func:`bluesky.plans.rel_list_grid_scan` - """ - # TODO read initial positions (redundantly) so they can be put in md here - _md = {'plan_name': 'rel_list_scan'} - _md.update(md or {}) - - motors = [motor for motor, pos_list in partition(2, args)] - - @bpp.reset_positions_decorator(motors) - @bpp.relative_set_decorator(motors) - def inner_relative_list_scan(): - return (yield from list_scan(detectors, *args, per_step=per_step, - md=_md)) - return (yield from inner_relative_list_scan())
- - -
[docs]def list_grid_scan(detectors, *args, snake_axes=False, per_step=None, md=None): - """ - Scan over a mesh; each motor is on an independent trajectory. - - Parameters - ---------- - detectors: list - list of 'readable' objects - args: list - patterned like (``motor1, position_list1,`` - ``motor2, position_list2,`` - ``motor3, position_list3,`` - ``...,`` - ``motorN, position_listN``) - - The first motor is the "slowest", the outer loop. ``position_list``'s - are lists of positions, all lists must have the same length. Motors - can be any 'settable' object (motor, temp controller, etc.). - snake_axes: boolean or iterable, optional - which axes should be snaked, either ``False`` (do not snake any axes), - ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis - is defined as following snake-like, winding trajectory instead of a - simple left-to-right trajectory.The elements of the list are motors - that are listed in `args`. The list must not contain the slowest - (first) motor, since it can't be snaked. - per_step: callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md: dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_list_grid_scan` - :func:`bluesky.plans.list_scan` - :func:`bluesky.plans.rel_list_scan` - """ - - full_cycler = plan_patterns.outer_list_product(args, snake_axes) - - md_args = [] - motor_names = [] - motors = [] - for i, (motor, pos_list) in enumerate(partition(2, args)): - md_args.extend([repr(motor), pos_list]) - motor_names.append(motor.name) - motors.append(motor) - _md = {'shape': tuple(len(pos_list) - for motor, pos_list in partition(2, args)), - 'extents': tuple([min(pos_list), max(pos_list)] - for motor, pos_list in partition(2, args)), - 'snake_axes': snake_axes, - 'plan_args': {'detectors': list(map(repr, detectors)), - 'args': md_args, - 'per_step': repr(per_step)}, - 'plan_name': 'list_grid_scan', - 'plan_pattern': 'outer_list_product', - 'plan_pattern_args': dict(args=md_args).update( - {'snake_axes': snake_axes}), - 'plan_pattern_module': plan_patterns.__name__, - 'motors': tuple(motor_names), - 'hints': {}, - } - _md.update(md or {}) - try: - _md['hints'].setdefault('dimensions', [(m.hints['fields'], 'primary') - for m in motors]) - except (AttributeError, KeyError): - ... - - return (yield from scan_nd(detectors, full_cycler, - per_step=per_step, md=_md))
- - -
[docs]def rel_list_grid_scan(detectors, *args, snake_axes=False, per_step=None, - md=None): - """ - Scan over a mesh; each motor is on an independent trajectory. Each point is - relative to the current position. - - Parameters - ---------- - detectors : list - list of 'readable' objects - - args - patterned like (``motor1, position_list1,`` - ``motor2, position_list2,`` - ``motor3, position_list3,`` - ``...,`` - ``motorN, position_listN``) - - The first motor is the "slowest", the outer loop. ``position_list``'s - are lists of positions, all lists must have the same length. Motors - can be any 'settable' object (motor, temp controller, etc.). - - snake_axes : boolean or Iterable, optional - which axes should be snaked, either ``False`` (do not snake any axes), - ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis - is defined as following snake-like, winding trajectory instead of a - simple left-to-right trajectory.The elements of the list are motors - that are listed in `args`. The list must not contain the slowest - (first) motor, since it can't be snaked. - - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.list_grid_scan` - :func:`bluesky.plans.list_scan` - :func:`bluesky.plans.rel_list_scan` - """ - _md = {'plan_name': 'rel_list_grid_scan'} - _md.update(md or {}) - - motors = [motor for motor, pos_list in partition(2, args)] - - @bpp.reset_positions_decorator(motors) - @bpp.relative_set_decorator(motors) - def inner_relative_list_grid_scan(): - return (yield from list_grid_scan(detectors, *args, - snake_axes=snake_axes, - per_step=per_step, md=_md)) - return (yield from inner_relative_list_grid_scan())
- - -def _scan_1d(detectors, motor, start, stop, num, *, per_step=None, md=None): - """ - Scan over one variable in equally spaced steps. - - Parameters - ---------- - detectors : list - list of 'readable' objects - motor : object - any 'settable' object (motor, temp controller, etc.) - start : float - starting position of motor - stop : float - ending position of motor - num : int - number of steps - per_step : callable, optional - hook for customizing action of inner loop (messages per step) - Expected signature: ``f(detectors, motor, step)`` - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_scan` - """ - _md = {'detectors': [det.name for det in detectors], - 'motors': [motor.name], - 'num_points': num, - 'num_intervals': num - 1, - 'plan_args': {'detectors': list(map(repr, detectors)), 'num': num, - 'motor': repr(motor), - 'start': start, 'stop': stop, - 'per_step': repr(per_step)}, - 'plan_name': 'scan', - 'plan_pattern': 'linspace', - 'plan_pattern_module': 'numpy', - 'plan_pattern_args': dict(start=start, stop=stop, num=num), - 'hints': {}, - } - _md.update(md or {}) - try: - dimensions = [(motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].setdefault('dimensions', dimensions) - - if per_step is None: - per_step = bps.one_1d_step - - steps = np.linspace(**_md['plan_pattern_args']) - - @bpp.stage_decorator(list(detectors) + [motor]) - @bpp.run_decorator(md=_md) - def inner_scan(): - for step in steps: - yield from per_step(detectors, motor, step) - - return (yield from inner_scan()) - - -def _rel_scan_1d(detectors, motor, start, stop, num, *, per_step=None, - md=None): - """ - Scan over one variable in equally spaced steps relative to current positon. - - Parameters - ---------- - detectors : list - list of 'readable' objects - motor : object - any 'settable' object (motor, temp controller, etc.) - start : float - starting position of motor - stop : float - ending position of motor - num : int - number of steps - per_step : callable, optional - hook for customizing action of inner loop (messages per step) - Expected signature: ``f(detectors, motor, step)`` - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.scan` - """ - _md = {'plan_name': 'rel_scan'} - _md.update(md or {}) - # TODO read initial positions (redundantly) so they can be put in md here - - @bpp.reset_positions_decorator([motor]) - @bpp.relative_set_decorator([motor]) - def inner_relative_scan(): - return (yield from _scan_1d(detectors, motor, start, stop, - num, per_step=per_step, md=_md)) - - return (yield from inner_relative_scan()) - - -
[docs]def log_scan(detectors, motor, start, stop, num, *, per_step=None, md=None): - """ - Scan over one variable in log-spaced steps. - - Parameters - ---------- - detectors : list - list of 'readable' objects - motor : object - any 'settable' object (motor, temp controller, etc.) - start : float - starting position of motor - stop : float - ending position of motor - num : int - number of steps - per_step : callable, optional - hook for customizing action of inner loop (messages per step) - Expected signature: ``f(detectors, motor, step)`` - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_log_scan` - """ - _md = {'detectors': [det.name for det in detectors], - 'motors': [motor.name], - 'num_points': num, - 'num_intervals': num - 1, - 'plan_args': {'detectors': list(map(repr, detectors)), 'num': num, - 'start': start, 'stop': stop, 'motor': repr(motor), - 'per_step': repr(per_step)}, - 'plan_name': 'log_scan', - 'plan_pattern': 'logspace', - 'plan_pattern_module': 'numpy', - 'plan_pattern_args': dict(start=start, stop=stop, num=num), - 'hints': {}, - } - _md.update(md or {}) - - try: - dimensions = [(motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].setdefault('dimensions', dimensions) - - if per_step is None: - per_step = bps.one_1d_step - - steps = np.logspace(**_md['plan_pattern_args']) - - @bpp.stage_decorator(list(detectors) + [motor]) - @bpp.run_decorator(md=_md) - def inner_log_scan(): - for step in steps: - yield from per_step(detectors, motor, step) - - return (yield from inner_log_scan())
- - -
[docs]def rel_log_scan(detectors, motor, start, stop, num, *, per_step=None, - md=None): - """ - Scan over one variable in log-spaced steps relative to current position. - - Parameters - ---------- - detectors : list - list of 'readable' objects - motor : object - any 'settable' object (motor, temp controller, etc.) - start : float - starting position of motor - stop : float - ending position of motor - num : int - number of steps - per_step : callable, optional - hook for customizing action of inner loop (messages per step) - Expected signature: ``f(detectors, motor, step)`` - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.log_scan` - """ - # TODO read initial positions (redundantly) so they can be put in md here - _md = {'plan_name': 'rel_log_scan'} - _md.update(md or {}) - - @bpp.reset_positions_decorator([motor]) - @bpp.relative_set_decorator([motor]) - def inner_relative_log_scan(): - return (yield from log_scan(detectors, motor, start, stop, num, - per_step=per_step, md=_md)) - - return (yield from inner_relative_log_scan())
- - -
[docs]def adaptive_scan(detectors, target_field, motor, start, stop, - min_step, max_step, target_delta, backstep, - threshold=0.8, *, md=None): - """ - Scan over one variable with adaptively tuned step size. - - Parameters - ---------- - detectors : list - list of 'readable' objects - target_field : string - data field whose output is the focus of the adaptive tuning - motor : object - any 'settable' object (motor, temp controller, etc.) - start : float - starting position of motor - stop : float - ending position of motor - min_step : float - smallest step for fast-changing regions - max_step : float - largest step for slow-chaning regions - target_delta : float - desired fractional change in detector signal between steps - backstep : bool - whether backward steps are allowed -- this is concern with some motors - threshold : float, optional - threshold for going backward and rescanning a region, default is 0.8 - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_adaptive_scan` - """ - if not 0 < min_step < max_step: - raise ValueError("min_step and max_step must meet condition of " - "max_step > min_step > 0") - - _md = {'detectors': [det.name for det in detectors], - 'motors': [motor.name], - 'plan_args': {'detectors': list(map(repr, detectors)), - 'motor': repr(motor), - 'start': start, - 'stop': stop, - 'min_step': min_step, - 'max_step': max_step, - 'target_delta': target_delta, - 'backstep': backstep, - 'threshold': threshold}, - 'plan_name': 'adaptive_scan', - 'hints': {}, - } - _md.update(md or {}) - try: - dimensions = [(motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].setdefault('dimensions', dimensions) - - @bpp.stage_decorator(list(detectors) + [motor]) - @bpp.run_decorator(md=_md) - def adaptive_core(): - next_pos = start - step = (max_step - min_step) / 2 - past_I = None - cur_I = None - cur_det = {} - if stop >= start: - direction_sign = 1 - else: - direction_sign = -1 - while next_pos * direction_sign < stop * direction_sign: - yield Msg('checkpoint') - yield from bps.mv(motor, next_pos) - yield Msg('create', None, name='primary') - for det in detectors: - yield Msg('trigger', det, group='B') - yield Msg('wait', None, 'B') - for det in utils.separate_devices(detectors + [motor]): - cur_det = yield Msg('read', det) - if target_field in cur_det: - cur_I = cur_det[target_field]['value'] - yield Msg('save') - - # special case first first loop - if past_I is None: - past_I = cur_I - next_pos += step * direction_sign - continue - - dI = np.abs(cur_I - past_I) - - slope = dI / step - if slope: - new_step = np.clip(target_delta / slope, min_step, max_step) - else: - new_step = np.min([step * 1.1, max_step]) - - # if we over stepped, go back and try again - if backstep and (new_step < step * threshold): - next_pos -= step - step = new_step - else: - past_I = cur_I - step = 0.2 * new_step + 0.8 * step - next_pos += step * direction_sign - - return (yield from adaptive_core())
- - -
[docs]def rel_adaptive_scan(detectors, target_field, motor, start, stop, - min_step, max_step, target_delta, backstep, - threshold=0.8, *, md=None): - """ - Relative scan over one variable with adaptively tuned step size. - - Parameters - ---------- - detectors : list - list of 'readable' objects - target_field : string - data field whose output is the focus of the adaptive tuning - motor : object - any 'settable' object (motor, temp controller, etc.) - start : float - starting position of motor - stop : float - ending position of motor - min_step : float - smallest step for fast-changing regions - max_step : float - largest step for slow-chaning regions - target_delta : float - desired fractional change in detector signal between steps - backstep : bool - whether backward steps are allowed -- this is concern with some motors - threshold : float, optional - threshold for going backward and rescanning a region, default is 0.8 - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.adaptive_scan` - """ - _md = {'plan_name': 'rel_adaptive_scan'} - _md.update(md or {}) - - @bpp.reset_positions_decorator([motor]) - @bpp.relative_set_decorator([motor]) - def inner_relative_adaptive_scan(): - return (yield from adaptive_scan(detectors, target_field, - motor, start, stop, min_step, - max_step, target_delta, - backstep, threshold, md=_md)) - - return (yield from inner_relative_adaptive_scan())
- - -
[docs]def tune_centroid( - detectors, signal, motor, - start, stop, min_step, - num=10, - step_factor=3.0, - snake=False, - *, md=None): - r""" - plan: tune a motor to the centroid of signal(motor) - - Initially, traverse the range from start to stop with - the number of points specified. Repeat with progressively - smaller step size until the minimum step size is reached. - Rescans will be centered on the signal centroid - (for $I(x)$, centroid$= \sum{I}/\sum{x*I}$) - with original scan range reduced by ``step_factor``. - - Set ``snake=True`` if your positions are reproducible - moving from either direction. This will not necessarily - decrease the number of traversals required to reach convergence. - Snake motion reduces the total time spent on motion - to reset the positioner. For some positioners, such as - those with hysteresis, snake scanning may not be appropriate. - For such positioners, always approach the positions from the - same direction. - - Note: Ideally the signal has only one peak in the range to - be scanned. It is assumed the signal is not polymodal - between ``start`` and ``stop``. - - Parameters - ---------- - detectors : Signal - list of 'readable' objects - signal : string - detector field whose output is to maximize - motor : object - any 'settable' object (motor, temp controller, etc.) - start : float - start of range - stop : float - end of range, note: start < stop - min_step : float - smallest step size to use. - num : int, optional - number of points with each traversal, default = 10 - step_factor : float, optional - used in calculating new range after each pass - - note: step_factor > 1.0, default = 3 - snake : bool, optional - if False (default), always scan from start to stop - md : dict, optional - metadata - - Examples - -------- - Find the center of a peak using synthetic hardware. - - >>> from ophyd.sim import SynAxis, SynGauss - >>> motor = SynAxis(name='motor') - >>> det = SynGauss(name='det', motor, 'motor', - ... center=-1.3, Imax=1e5, sigma=0.05) - >>> RE(tune_centroid([det], "det", motor, -1.5, -0.5, 0.01, 10)) - """ - if min_step <= 0: - raise ValueError("min_step must be positive") - if step_factor <= 1.0: - raise ValueError("step_factor must be greater than 1.0") - try: - motor_name, = motor.hints['fields'] - except (AttributeError, ValueError): - motor_name = motor.name - _md = {'detectors': [det.name for det in detectors], - 'motors': [motor.name], - 'plan_args': {'detectors': list(map(repr, detectors)), - 'motor': repr(motor), - 'start': start, - 'stop': stop, - 'num': num, - 'min_step': min_step, }, - 'plan_name': 'tune_centroid', - 'hints': {}, - } - _md.update(md or {}) - try: - dimensions = [(motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].setdefault('dimensions', dimensions) - - low_limit = min(start, stop) - high_limit = max(start, stop) - - @bpp.stage_decorator(list(detectors) + [motor]) - @bpp.run_decorator(md=_md) - def _tune_core(start, stop, num, signal): - next_pos = start - step = (stop - start) / (num - 1) - peak_position = None - cur_I = None - sum_I = 0 # for peak centroid calculation, I(x) - sum_xI = 0 - - while abs(step) >= min_step and low_limit <= next_pos <= high_limit: - yield Msg('checkpoint') - yield from bps.mv(motor, next_pos) - ret = (yield from bps.trigger_and_read(detectors + [motor])) - cur_I = ret[signal]['value'] - sum_I += cur_I - position = ret[motor_name]['value'] - sum_xI += position * cur_I - - next_pos += step - in_range = min(start, stop) <= next_pos <= max(start, stop) - - if not in_range: - if sum_I == 0: - return - peak_position = sum_xI / sum_I # centroid - sum_I, sum_xI = 0, 0 # reset for next pass - new_scan_range = (stop - start) / step_factor - start = np.clip(peak_position - new_scan_range/2, - low_limit, high_limit) - stop = np.clip(peak_position + new_scan_range/2, - low_limit, high_limit) - if snake: - start, stop = stop, start - step = (stop - start) / (num - 1) - next_pos = start - # print("peak position = {}".format(peak_position)) - # print("start = {}".format(start)) - # print("stop = {}".format(stop)) - - # finally, move to peak position - if peak_position is not None: - # improvement: report final peak_position - # print("final position = {}".format(peak_position)) - yield from bps.mv(motor, peak_position) - - return (yield from _tune_core(start, stop, num, signal))
- - -
[docs]def scan_nd(detectors, cycler, *, per_step=None, md=None): - """ - Scan over an arbitrary N-dimensional trajectory. - - Parameters - ---------- - detectors : list - cycler : Cycler - cycler.Cycler object mapping movable interfaces to positions - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.inner_product_scan` - :func:`bluesky.plans.grid_scan` - - Examples - -------- - >>> from cycler import cycler - >>> cy = cycler(motor1, [1, 2, 3]) * cycler(motor2, [4, 5, 6]) - >>> scan_nd([sensor], cy) - """ - _md = {'detectors': [det.name for det in detectors], - 'motors': [motor.name for motor in cycler.keys], - 'num_points': len(cycler), - 'num_intervals': len(cycler) - 1, - 'plan_args': {'detectors': list(map(repr, detectors)), - 'cycler': repr(cycler), - 'per_step': repr(per_step)}, - 'plan_name': 'scan_nd', - 'hints': {}, - } - _md.update(md or {}) - try: - dimensions = [(motor.hints['fields'], 'primary') - for motor in cycler.keys] - except (AttributeError, KeyError): - # Not all motors provide a 'fields' hint, so we have to skip it. - pass - else: - # We know that hints exists. Either: - # - the user passed it in and we are extending it - # - the user did not pass it in and we got the default {} - # If the user supplied hints includes a dimension entry, do not - # change it, else set it to the one generated above - _md['hints'].setdefault('dimensions', dimensions) - - if per_step is None: - per_step = bps.one_nd_step - else: - # Ensure that the user-defined per-step has the expected signature. - sig = inspect.signature(per_step) - - def _verify_1d_step(sig): - if len(sig.parameters) < 3: - return False - for name, (p_name, p) in zip_longest(['detectors', 'motor', 'step'], sig.parameters.items()): - # this is one of the first 3 positional arguements, check that the name matches - if name is not None: - if name != p_name: - return False - # if there are any extra arguments, check that they have a default - else: - if p.kind is p.VAR_KEYWORD or p.kind is p.VAR_POSITIONAL: - continue - if p.default is p.empty: - return False - - return True - - def _verify_nd_step(sig): - if len(sig.parameters) < 3: - return False - for name, (p_name, p) in zip_longest(['detectors', 'step', 'pos_cache'], sig.parameters.items()): - # this is one of the first 3 positional arguements, check that the name matches - if name is not None: - if name != p_name: - return False - # if there are any extra arguments, check that they have a default - else: - if p.kind is p.VAR_KEYWORD or p.kind is p.VAR_POSITIONAL: - continue - if p.default is p.empty: - return False - - return True - - if sig == inspect.signature(bps.one_nd_step): - pass - elif _verify_nd_step(sig): - # check other signature for back-compatibility - pass - elif _verify_1d_step(sig): - # Accept this signature for back-compat reasons (because - # inner_product_scan was renamed scan). - dims = len(list(cycler.keys)) - if dims != 1: - raise TypeError("Signature of per_step assumes 1D trajectory " - "but {} motors are specified.".format(dims)) - motor, = cycler.keys - user_per_step = per_step - - def adapter(detectors, step, pos_cache): - # one_nd_step 'step' parameter is a dict; one_id_step 'step' - # parameter is a value - step, = step.values() - return (yield from user_per_step(detectors, motor, step)) - per_step = adapter - else: - raise TypeError("per_step must be a callable with the signature \n " - "<Signature (detectors, step, pos_cache)> or " - "<Signature (detectors, motor, step)>. \n" - "per_step signature received: {}".format(sig)) - pos_cache = defaultdict(lambda: None) # where last position is stashed - cycler = utils.merge_cycler(cycler) - motors = list(cycler.keys) - - @bpp.stage_decorator(list(detectors) + motors) - @bpp.run_decorator(md=_md) - def inner_scan_nd(): - for step in list(cycler): - yield from per_step(detectors, step, pos_cache) - - return (yield from inner_scan_nd())
- - -def inner_product_scan(detectors, num, *args, per_step=None, md=None): - # For scan, num is the _last_ positional arg instead of the first one. - # Notice the swapped order here. - md = md or {} - md.setdefault('plan_name', 'inner_product_scan') - yield from scan(detectors, *args, num, per_step=None, md=md) - - -
[docs]def scan(detectors, *args, num=None, per_step=None, md=None): - """ - Scan over one multi-motor trajectory. - - Parameters - ---------- - detectors : list - list of 'readable' objects - *args : - For one dimension, ``motor, start, stop``. - In general: - - .. code-block:: python - - motor1, start1, stop1, - motor2, start2, start2, - ..., - motorN, startN, stopN - - Motors can be any 'settable' object (motor, temp controller, etc.) - num : integer - number of points - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.relative_inner_product_scan` - :func:`bluesky.plans.grid_scan` - :func:`bluesky.plans.scan_nd` - """ - # For back-compat reasons, we accept 'num' as the last positional argument: - # scan(detectors, motor, -1, 1, 3) - # or by keyword: - # scan(detectors, motor, -1, 1, num=3) - # ... which requires some special processing. - if num is None: - if len(args) % 3 != 1: - raise ValueError("The number of points to scan must be provided " - "as the last positional argument or as keyword " - "argument 'num'.") - num = args[-1] - args = args[:-1] - - if not (float(num).is_integer() and num > 0.0): - raise ValueError(f"The parameter `num` is expected to be a number of " - f"steps (not step size!) It must therefore be a " - f"whole number. The given value was {num}.") - num = int(num) - - md_args = list(chain(*((repr(motor), start, stop) - for motor, start, stop in partition(3, args)))) - motor_names = tuple(motor.name for motor, start, stop - in partition(3, args)) - md = md or {} - _md = {'plan_args': {'detectors': list(map(repr, detectors)), - 'num': num, 'args': md_args, - 'per_step': repr(per_step)}, - 'plan_name': 'scan', - 'plan_pattern': 'inner_product', - 'plan_pattern_module': plan_patterns.__name__, - 'plan_pattern_args': dict(num=num, args=md_args), - 'motors': motor_names - } - _md.update(md) - - # get hints for best effort callback - motors = [motor for motor, start, stop in partition(3, args)] - - # Give a hint that the motors all lie along the same axis - # [(['motor1', 'motor2', ...], 'primary'), ] is 1D (this case) - # [ ('motor1', 'primary'), ('motor2', 'primary'), ... ] is 2D for example - # call x_fields because these are meant to be the x (independent) axis - x_fields = [] - for motor in motors: - x_fields.extend(getattr(motor, 'hints', {}).get('fields', [])) - - default_dimensions = [(x_fields, 'primary')] - - default_hints = {} - if len(x_fields) > 0: - default_hints.update(dimensions=default_dimensions) - - # now add default_hints and override any hints from the original md (if - # exists) - _md['hints'] = default_hints - _md['hints'].update(md.get('hints', {}) or {}) - - full_cycler = plan_patterns.inner_product(num=num, args=args) - - return (yield from scan_nd(detectors, full_cycler, - per_step=per_step, md=_md))
- - -
[docs]def grid_scan(detectors, *args, snake_axes=None, per_step=None, md=None): - """ - Scan over a mesh; each motor is on an independent trajectory. - - Parameters - ---------- - detectors: list - list of 'readable' objects - ``*args`` - patterned like (``motor1, start1, stop1, num1,`` - ``motor2, start2, stop2, num2,`` - ``motor3, start3, stop3, num3,`` ... - ``motorN, startN, stopN, numN``) - - The first motor is the "slowest", the outer loop. For all motors - except the first motor, there is a "snake" argument: a boolean - indicating whether to following snake-like, winding trajectory or a - simple left-to-right trajectory. - snake_axes: boolean or iterable, optional - which axes should be snaked, either ``False`` (do not snake any axes), - ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis - is defined as following snake-like, winding trajectory instead of a - simple left-to-right trajectory. The elements of the list are motors - that are listed in `args`. The list must not contain the slowest - (first) motor, since it can't be snaked. - per_step: callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md: dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_grid_scan` - :func:`bluesky.plans.inner_product_scan` - :func:`bluesky.plans.scan_nd` - """ - # Notes: (not to be included in the documentation) - # The deprecated function call with no 'snake_axes' argument and 'args' - # patterned like (``motor1, start1, stop1, num1,`` - # ``motor2, start2, stop2, num2, snake2,`` - # ``motor3, start3, stop3, num3, snake3,`` ... - # ``motorN, startN, stopN, numN, snakeN``) - # The first motor is the "slowest", the outer loop. For all motors - # except the first motor, there is a "snake" argument: a boolean - # indicating whether to following snake-like, winding trajectory or a - # simple left-to-right trajectory. - # Ideally, deprecated and new argument lists should not be mixed. - # The function will still accept `args` in the old format even if `snake_axes` is - # supplied, but if `snake_axes` is not `None` (the default value), it overrides - # any values of `snakeX` in `args`. - - args_pattern = plan_patterns.classify_outer_product_args_pattern(args) - if (snake_axes is not None) and \ - (args_pattern == plan_patterns.OuterProductArgsPattern.PATTERN_2): - raise ValueError("Mixing of deprecated and new API interface is not allowed: " - "the parameter 'snake_axes' can not be used if snaking is " - "set as part of 'args'") - - # For consistency, set 'snake_axes' to False if new API call is detected - if (snake_axes is None) and \ - (args_pattern != plan_patterns.OuterProductArgsPattern.PATTERN_2): - snake_axes = False - - chunk_args = list(plan_patterns.chunk_outer_product_args(args, args_pattern)) - # 'chunk_args' is a list of tuples of the form: (motor, start, stop, num, snake) - # If the function is called using deprecated pattern for arguments, then - # 'snake' may be set True for some motors, otherwise the 'snake' is always False. - - # The list of controlled motors - motors = [_[0] for _ in chunk_args] - - # Check that the same motor is not listed multiple times. This indicates an error in the script. - if len(set(motors)) != len(motors): - raise ValueError(f"Some motors are listed multiple times in the argument list 'args': " - f"'{motors}'") - - if snake_axes is not None: - - def _set_snaking(chunk, value): - """Returns the tuple `chunk` with modified 'snake' value""" - _motor, _start, _stop, _num, _snake = chunk - return _motor, _start, _stop, _num, value - - if isinstance(snake_axes, collections.abc.Iterable) and not isinstance(snake_axes, str): - # Always convert to a tuple (in case a `snake_axes` is an iterator). - snake_axes = tuple(snake_axes) - - # Check if the list of axes (motors) contains repeated entries. - if len(set(snake_axes)) != len(snake_axes): - raise ValueError(f"The list of axes 'snake_axes' contains repeated elements: " - f"'{snake_axes}'") - - # Check if the snaking is enabled for the slowest motor. - if len(motors) and (motors[0] in snake_axes): - raise ValueError(f"The list of axes 'snake_axes' contains the slowest motor: " - f"'{snake_axes}'") - - # Check that all motors in the chunk_args are controlled in the scan. - # It is very likely that the script running the plan has a bug. - if any([_ not in motors for _ in snake_axes]): - raise ValueError(f"The list of axes 'snake_axes' contains motors " - f"that are not controlled during the scan: " - f"'{snake_axes}'") - - # Enable snaking for the selected axes. - # If the argument `snake_axes` is specified (not None), then - # any `snakeX` values that could be specified in `args` are ignored. - for n, chunk in enumerate(chunk_args): - if n > 0: # The slowest motor is never snaked - motor = chunk[0] - if motor in snake_axes: - chunk_args[n] = _set_snaking(chunk, True) - else: - chunk_args[n] = _set_snaking(chunk, False) - - elif snake_axes is True: # 'snake_axes' has boolean value `True` - # Set all 'snake' values except for the slowest motor - chunk_args = [_set_snaking(_, True) if n > 0 else _ - for n, _ in enumerate(chunk_args)] - elif snake_axes is False: # 'snake_axes' has boolean value `True` - # Set all 'snake' values - chunk_args = [_set_snaking(_, False) for _ in chunk_args] - else: - raise ValueError(f"Parameter 'snake_axes' is not iterable, boolean or None: " - f"'{snake_axes}', type: {type(snake_axes)}") - - # Prepare the argument list for the `outer_product` function - args_modified = [] - for n, chunk in enumerate(chunk_args): - if n == 0: - args_modified.extend(chunk[:-1]) - else: - args_modified.extend(chunk) - full_cycler = plan_patterns.outer_product(args=args_modified) - - md_args = [] - motor_names = [] - motors = [] - for i, (motor, start, stop, num, snake) in enumerate(chunk_args): - md_args.extend([repr(motor), start, stop, num]) - if i > 0: - # snake argument only shows up after the first motor - md_args.append(snake) - motor_names.append(motor.name) - motors.append(motor) - _md = {'shape': tuple(num for motor, start, stop, num, snake - in chunk_args), - 'extents': tuple([start, stop] for motor, start, stop, num, snake - in chunk_args), - 'snaking': tuple(snake for motor, start, stop, num, snake - in chunk_args), - # 'num_points': inserted by scan_nd - 'plan_args': {'detectors': list(map(repr, detectors)), - 'args': md_args, - 'per_step': repr(per_step)}, - 'plan_name': 'grid_scan', - 'plan_pattern': 'outer_product', - 'plan_pattern_args': dict(args=md_args), - 'plan_pattern_module': plan_patterns.__name__, - 'motors': tuple(motor_names), - 'hints': {}, - } - _md.update(md or {}) - _md['hints'].setdefault('gridding', 'rectilinear') - try: - _md['hints'].setdefault('dimensions', [(m.hints['fields'], 'primary') - for m in motors]) - except (AttributeError, KeyError): - ... - - return (yield from scan_nd(detectors, full_cycler, - per_step=per_step, md=_md))
- - -
[docs]def rel_grid_scan(detectors, *args, snake_axes=None, per_step=None, md=None): - """ - Scan over a mesh relative to current position. - - Parameters - ---------- - detectors: list - list of 'readable' objects - ``*args`` - patterned like (``motor1, start1, stop1, num1,`` - ``motor2, start2, stop2, num2,`` - ``motor3, start3, stop3, num3,`` ... - ``motorN, startN, stopN, numN``) - - The first motor is the "slowest", the outer loop. For all motors - except the first motor, there is a "snake" argument: a boolean - indicating whether to following snake-like, winding trajectory or a - simple left-to-right trajectory. - snake_axes: boolean or iterable, optional - which axes should be snaked, either ``False`` (do not snake any axes), - ``True`` (snake all axes) or a list of axes to snake. "Snaking" an axis - is defined as following snake-like, winding trajectory instead of a - simple left-to-right trajectory. The elements of the list are motors - that are listed in `args`. The list must not contain the slowest - (first) motor, since it can't be snaked. - per_step: callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md: dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.relative_inner_product_scan` - :func:`bluesky.plans.grid_scan` - :func:`bluesky.plans.scan_nd` - """ - # Notes: the deprecated function call is also supported. See the notes - # following the docstring for 'grid_scan' function - - _md = {'plan_name': 'rel_grid_scan'} - _md.update(md or {}) - motors = [m[0] for m in - plan_patterns.chunk_outer_product_args(args)] - - @bpp.reset_positions_decorator(motors) - @bpp.relative_set_decorator(motors) - def inner_rel_grid_scan(): - return (yield from grid_scan(detectors, *args, - snake_axes=snake_axes, - per_step=per_step, md=_md)) - - return (yield from inner_rel_grid_scan())
- - -def relative_inner_product_scan(detectors, num, *args, per_step=None, md=None): - # For rel_scan, num is the _last_ positional arg instead of the first one. - # Notice the swapped order here. - md = md or {} - md.setdefault('plan_name', 'relative_inner_product_scan') - yield from rel_scan(detectors, *args, num, per_step=per_step, md=md) - - -
[docs]def rel_scan(detectors, *args, num=None, per_step=None, md=None): - """ - Scan over one multi-motor trajectory relative to current position. - - Parameters - ---------- - detectors : list - list of 'readable' objects - *args : - For one dimension, ``motor, start, stop``. - In general: - - .. code-block:: python - - motor1, start1, stop1, - motor2, start2, start2, - ..., - motorN, startN, stopN, - - Motors can be any 'settable' object (motor, temp controller, etc.) - num : integer - number of points - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_grid_scan` - :func:`bluesky.plans.inner_product_scan` - :func:`bluesky.plans.scan_nd` - """ - _md = {'plan_name': 'rel_scan'} - md = md or {} - _md.update(md) - motors = [motor for motor, start, stop in partition(3, args)] - - @bpp.reset_positions_decorator(motors) - @bpp.relative_set_decorator(motors) - def inner_rel_scan(): - return (yield from scan(detectors, *args, num=num, - per_step=per_step, md=_md)) - - return (yield from inner_rel_scan())
- - -
[docs]def tweak(detector, target_field, motor, step, *, md=None): - """ - Move and motor and read a detector with an interactive prompt. - - Parameters - ---------- - detetector : Device - target_field : string - data field whose output is the focus of the adaptive tuning - motor : Device - step : float - initial suggestion for step size - md : dict, optional - metadata - """ - prompt_str = '{0}, {1:.3}, {2:.3}, ({3}) ' - - _md = {'detectors': [detector.name], - 'motors': [motor.name], - 'plan_args': {'detector': repr(detector), - 'target_field': target_field, - 'motor': repr(motor), - 'step': step}, - 'plan_name': 'tweak', - 'hints': {}, - } - try: - dimensions = [(motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].update({'dimensions': dimensions}) - _md.update(md or {}) - d = detector - try: - from IPython.display import clear_output - except ImportError: - # Define a no-op for clear_output. - def clear_output(wait=False): - pass - - @bpp.stage_decorator([detector, motor]) - @bpp.run_decorator(md=_md) - def tweak_core(): - nonlocal step - - while True: - yield Msg('create', None, name='primary') - ret_mot = yield Msg('read', motor) - if ret_mot is None: - return - key = list(ret_mot.keys())[0] - pos = ret_mot[key]['value'] - yield Msg('trigger', d, group='A') - yield Msg('wait', None, 'A') - reading = yield Msg('read', d) - val = reading[target_field]['value'] - yield Msg('save') - prompt = prompt_str.format(motor.name, float(pos), - float(val), step) - new_step = yield Msg('input', prompt=prompt) - if new_step: - try: - step = float(new_step) - except ValueError: - break - yield Msg('set', motor, pos + step, group='A') - print('Motor moving...') - sys.stdout.flush() - yield Msg('wait', None, 'A') - clear_output(wait=True) - # stackoverflow.com/a/12586667/380231 - print('\x1b[1A\x1b[2K\x1b[1A') - - return (yield from tweak_core())
- - -
[docs]def spiral_fermat(detectors, x_motor, y_motor, x_start, y_start, x_range, - y_range, dr, factor, *, dr_y=None, tilt=0.0, per_step=None, - md=None): - '''Absolute fermat spiral scan, centered around (x_start, y_start) - - Parameters - ---------- - detectors : list - list of 'readable' objects - x_motor : object - any 'settable' object (motor, temp controller, etc.) - y_motor : object - any 'settable' object (motor, temp controller, etc.) - x_start : float - x center - y_start : float - y center - x_range : float - x width of spiral - y_range : float - y width of spiral - dr : float - delta radius - factor : float - radius gets divided by this - dr_y : float, optional - Delta radius along the major axis of the ellipse, if not specifed - defaults to dr. - tilt : float, optional - Tilt angle in radians, default 0.0 - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.spiral` - :func:`bluesky.plans.rel_spiral` - :func:`bluesky.plans.rel_spiral_fermat` - ''' - pattern_args = dict(x_motor=x_motor, y_motor=y_motor, x_start=x_start, - y_start=y_start, x_range=x_range, y_range=y_range, - dr=dr, factor=factor, dr_y=dr_y, tilt=tilt) - cyc = plan_patterns.spiral_fermat(**pattern_args) - - # Before including pattern_args in metadata, replace objects with reprs. - pattern_args['x_motor'] = repr(x_motor) - pattern_args['y_motor'] = repr(y_motor) - _md = {'plan_args': {'detectors': list(map(repr, detectors)), - 'x_motor': repr(x_motor), 'y_motor': repr(y_motor), - 'x_start': x_start, 'y_start': y_start, - 'x_range': x_range, 'y_range': y_range, - 'dr': dr, 'factor': factor, 'dr_y': dr_y, - 'tilt': tilt, 'per_step': repr(per_step)}, - 'extents': tuple([[x_start - x_range, x_start + x_range], - [y_start - y_range, y_start + y_range]]), - 'plan_name': 'spiral_fermat', - 'plan_pattern': 'spiral_fermat', - 'plan_pattern_module': plan_patterns.__name__, - 'plan_pattern_args': pattern_args, - 'hints': {}, - } - try: - dimensions = [(x_motor.hints['fields'], 'primary'), - (y_motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].update({'dimensions': dimensions}) - _md.update(md or {}) - - return (yield from scan_nd(detectors, cyc, per_step=per_step, md=_md))
- - -
[docs]def rel_spiral_fermat(detectors, x_motor, y_motor, x_range, y_range, dr, - factor, *, dr_y=None, tilt=0.0, per_step=None, md=None): - '''Relative fermat spiral scan - - Parameters - ---------- - detectors : list - list of 'readable' objects - x_motor : object - any 'settable' object (motor, temp controller, etc.) - y_motor : object - any 'settable' object (motor, temp controller, etc.) - x_range : float - x width of spiral - y_range : float - y width of spiral - dr : float - delta radius - factor : float - radius gets divided by this - dr_y : float, optional - Delta radius along the major axis of the ellipse, if not specifed - defaults to dr - tilt : float, optional - Tilt angle in radians, default 0.0 - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.spiral` - :func:`bluesky.plans.rel_spiral` - :func:`bluesky.plans.spiral_fermat` - ''' - _md = {'plan_name': 'rel_spiral_fermat'} - _md.update(md or {}) - - @bpp.reset_positions_decorator([x_motor, y_motor]) - @bpp.relative_set_decorator([x_motor, y_motor]) - def inner_relative_spiral_fermat(): - return (yield from spiral_fermat(detectors, x_motor, y_motor, - 0, 0, - x_range, y_range, - dr, factor, dr_y=dr_y, tilt=tilt, - per_step=per_step, md=_md)) - - return (yield from inner_relative_spiral_fermat())
- - -
[docs]def spiral(detectors, x_motor, y_motor, x_start, y_start, x_range, y_range, dr, - nth, *, dr_y=None, tilt=0.0, per_step=None, md=None): - '''Spiral scan, centered around (x_start, y_start) - - Parameters - ---------- - x_motor : object - any 'settable' object (motor, temp controller, etc.) - y_motor : object - any 'settable' object (motor, temp controller, etc.) - x_start : float - x center - y_start : float - y center - x_range : float - x width of spiral - y_range : float - y width of spiral - dr : float - Delta radius along the minor axis of the ellipse. - dr_y : float, optional - Delta radius along the major axis of the ellipse. If None, defaults to - dr. - nth : float - Number of theta steps - tilt : float, optional - Tilt angle in radians, default 0.0 - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.rel_spiral` - :func:`bluesky.plans.spiral_fermat` - :func:`bluesky.plans.rel_spiral_fermat` - ''' - pattern_args = dict(x_motor=x_motor, y_motor=y_motor, x_start=x_start, - y_start=y_start, x_range=x_range, y_range=y_range, - dr=dr, nth=nth, dr_y=dr_y, tilt=tilt) - cyc = plan_patterns.spiral(**pattern_args) - - # Before including pattern_args in metadata, replace objects with reprs. - pattern_args['x_motor'] = repr(x_motor) - pattern_args['y_motor'] = repr(y_motor) - _md = {'plan_args': {'detectors': list(map(repr, detectors)), - 'x_motor': repr(x_motor), 'y_motor': repr(y_motor), - 'x_start': x_start, 'y_start': y_start, - 'x_range': x_range, 'y_range': y_range, - 'dr': dr, 'dr_y': dr_y, 'nth': nth, 'tilt': tilt, - 'per_step': repr(per_step)}, - 'extents': tuple([[x_start - x_range, x_start + x_range], - [y_start - y_range, y_start + y_range]]), - 'plan_name': 'spiral', - 'plan_pattern': 'spiral', - 'plan_pattern_args': pattern_args, - 'plan_pattern_module': plan_patterns.__name__, - 'hints': {}, - } - try: - dimensions = [(x_motor.hints['fields'], 'primary'), - (y_motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].update({'dimensions': dimensions}) - _md.update(md or {}) - - return (yield from scan_nd(detectors, cyc, per_step=per_step, md=_md))
- - -
[docs]def rel_spiral(detectors, x_motor, y_motor, x_range, y_range, dr, nth, - *, dr_y=None, tilt=0.0, per_step=None, md=None): - - '''Relative spiral scan - - Parameters - ---------- - x_motor : object - any 'settable' object (motor, temp controller, etc.) - y_motor : object - any 'settable' object (motor, temp controller, etc.) - x_range : float - x width of spiral - y_range : float - y width of spiral - dr : float - Delta radius along the minor axis of the ellipse. - dr_y : float, optional - Delta radius along the major axis of the ellipse. If None, it - defaults to dr. - nth : float - Number of theta steps - tilt : float, optional - Tilt angle in radians, default 0.0 - per_step : callable, optional - hook for customizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.spiral` - :func:`bluesky.plans.spiral_fermat` - ''' - _md = {'plan_name': 'rel_spiral'} - _md.update(md or {}) - - @bpp.reset_positions_decorator([x_motor, y_motor]) - @bpp.relative_set_decorator([x_motor, y_motor]) - def inner_relative_spiral(): - return (yield from spiral(detectors, x_motor, y_motor, - 0, 0, - x_range, y_range, dr, nth, - dr_y=dr_y, tilt=tilt, - per_step=per_step, md=_md)) - - return (yield from inner_relative_spiral())
- - -
[docs]def spiral_square(detectors, x_motor, y_motor, x_center, y_center, x_range, - y_range, x_num, y_num, *, per_step=None, md=None): - '''Absolute square spiral scan, centered around (x_center, y_center) - - Parameters - ---------- - detectors : list - list of 'readable' objects - x_motor : object - any 'settable' object (motor, temp controller, etc.) - y_motor : object - any 'settable' object (motor, temp controller, etc.) - x_center : float - x center - y_center : float - y center - x_range : float - x width of spiral - y_range : float - y width of spiral - x_num : float - number of x axis points - y_num : float - Number of y axis points. - per_step : callable, optional - hook for cutomizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plans.one_nd_step` (the default) for - details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.relative_spiral_square` - :func:`bluesky.plans.spiral` - :func:`bluesky.plans.relative_spiral` - :func:`bluesky.plans.spiral_fermat` - :func:`bluesky.plans.relative_spiral_fermat` - ''' - pattern_args = dict(x_motor=x_motor, y_motor=y_motor, x_center=x_center, - y_center=y_center, x_range=x_range, y_range=y_range, - x_num=x_num, y_num=y_num) - cyc = plan_patterns.spiral_square_pattern(**pattern_args) - - # Before including pattern_args in metadata, replace objects with reprs. - pattern_args['x_motor'] = repr(x_motor) - pattern_args['y_motor'] = repr(y_motor) - _md = {'plan_args': {'detectors': list(map(repr, detectors)), - 'x_motor': repr(x_motor), 'y_motor': repr(y_motor), - 'x_center': x_center, 'y_center': y_center, - 'x_range': x_range, 'y_range': y_range, - 'x_num': x_num, 'y_num': y_num, - 'per_step': repr(per_step)}, - 'plan_name': 'spiral_square', - 'plan_pattern': 'spiral_square', - 'shape': (y_num, x_num), - 'extents': ((y_center - y_range / 2, y_center + y_range / 2), - (x_center - x_range / 2, x_center + x_range / 2)), - 'hints': {}, - } - _md.update(md or {}) - _md['hints'].setdefault('gridding', 'rectilinear_nonsequential') - try: - _md['hints'].setdefault('dimensions', [(m.hints['fields'], 'primary') - for m in [y_motor, x_motor]]) - except (AttributeError, KeyError): - ... - - return (yield from scan_nd(detectors, cyc, per_step=per_step, md=_md))
- - -
[docs]def rel_spiral_square(detectors, x_motor, y_motor, x_range, y_range, - x_num, y_num, *, per_step=None, md=None): - '''Relative square spiral scan, centered around current (x, y) position. - - Parameters - ---------- - detectors : list - list of 'readable' objects - x_motor : object - any 'settable' object (motor, temp controller, etc.) - y_motor : object - any 'settable' object (motor, temp controller, etc.) - x_range : float - x width of spiral - y_range : float - y width of spiral - x_num : float - number of x axis points - y_num : float - Number of y axis points. - per_step : callable, optional - hook for cutomizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plans.one_nd_step` (the default) for - details. - md : dict, optional - metadata - - See Also - -------- - :func:`bluesky.plans.spiral_square` - :func:`bluesky.plans.spiral` - :func:`bluesky.plans.relative_spiral` - :func:`bluesky.plans.spiral_fermat` - :func:`bluesky.plans.relative_spiral_fermat` - ''' - _md = {'plan_name': 'rel_spiral_square'} - _md.update(md or {}) - - @bpp.reset_positions_decorator([x_motor, y_motor]) - @bpp.relative_set_decorator([x_motor, y_motor]) - def inner_relative_spiral(): - return (yield from spiral_square(detectors, x_motor, y_motor, - 0, 0, - x_range, y_range, x_num, y_num, - per_step=per_step, md=_md)) - - return (yield from inner_relative_spiral())
- - -
[docs]def ramp_plan(go_plan, - monitor_sig, - inner_plan_func, - take_pre_data=True, - timeout=None, - period=None, md=None): - '''Take data while ramping one or more positioners. - - The pseudo code for this plan is :: - - sts = (yield from go_plan) - - yield from open_run() - yield from inner_plan_func() - while not st.done: - yield from inner_plan_func() - yield from inner_plan_func() - - yield from close_run() - - Parameters - ---------- - go_plan : generator - plan to start the ramp. This will be run inside of a open/close - run. - - This plan must return a `ophyd.StatusBase` object. - - inner_plan_func : generator function - generator which takes no input - - This will be called for every data point. This should create - one or more events. - - timeout : float, optional - If not None, the maximum time the ramp can run. - - In seconds - - take_pre_data: Bool, optional - If True, add a pre data at beginning - - period : float, optional - If not None, take data no faster than this. If None, take - data as fast as possible - - If running the inner plan takes longer than `period` than take - data with no dead time. - - In seconds. - ''' - _md = {'plan_name': 'ramp_plan'} - _md.update(md or {}) - - @bpp.monitor_during_decorator((monitor_sig,)) - @bpp.run_decorator(md=_md) - def polling_plan(): - fail_time = None - if timeout is not None: - # sort out if we should watch the clock - fail_time = time.time() + timeout - - # take a 'pre' data point - if take_pre_data: - yield from inner_plan_func() - # start the ramp - status = (yield from go_plan) - - while not status.done: - start_time = time.time() - yield from inner_plan_func() - if fail_time is not None: - if time.time() > fail_time: - raise utils.RampFail() - if period is not None: - cur_time = time.time() - wait_time = (start_time + period) - cur_time - if wait_time > 0: - yield from bps.sleep(wait_time) - # take a 'post' data point - yield from inner_plan_func() - - return (yield from polling_plan())
- - -
[docs]def fly(flyers, *, md=None): - """ - Perform a fly scan with one or more 'flyers'. - - Parameters - ---------- - flyers : collection - objects that support the flyer interface - md : dict, optional - metadata - - Yields - ------ - msg : Msg - 'kickoff', 'wait', 'complete, 'wait', 'collect' messages - - See Also - -------- - :func:`bluesky.preprocessors.fly_during_wrapper` - :func:`bluesky.preprocessors.fly_during_decorator` - """ - uid = yield from bps.open_run(md) - for flyer in flyers: - yield from bps.kickoff(flyer, wait=True) - for flyer in flyers: - yield from bps.complete(flyer, wait=True) - for flyer in flyers: - yield from bps.collect(flyer) - yield from bps.close_run() - return uid
- - -def x2x_scan(detectors, motor1, motor2, start, stop, num, *, - per_step=None, md=None): - """ - Relatively scan over two motors in a 2:1 ratio - - This is a generalized version of a theta2theta scan - - Parameters - ---------- - detectors : list - list of 'readable' objects - - motor1, motor2 : Positioner - The second motor will move half as much as the first - - start, stop : float - The relative limits of the first motor. The second motor - will move between ``start / 2`` and ``stop / 2`` - - per_step : callable, optional - hook for cutomizing action of inner loop (messages per step). - See docstring of :func:`bluesky.plan_stubs.one_nd_step` (the default) - for details. - - md : dict, optional - metadata - - - """ - _md = {'plan_name': 'x2x_scan', - 'plan_args': {'detectors': list(map(repr, detectors)), - 'motor1': motor1.name, - 'motor2': motor2.name, - 'start': start, 'stop': stop, 'num': num, - 'per_step': repr(per_step)} - } - - _md.update(md or {}) - return (yield from relative_inner_product_scan( - detectors, num, - motor1, start, stop, - motor2, start / 2, stop / 2, - per_step=per_step, - md=_md)) - - -relative_list_scan = rel_list_scan # back-compat -relative_scan = rel_scan # back-compat -relative_log_scan = rel_log_scan # back-compat -relative_adaptive_scan = rel_adaptive_scan # back-compat -outer_product_scan = grid_scan # back-compat -relative_outer_product_scan = rel_grid_scan # back-compat -relative_spiral_fermat = rel_spiral_fermat # back-compat -relative_spiral = rel_spiral # back-compat -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/preprocessors.html b/bluesky/_modules/bluesky/preprocessors.html deleted file mode 100644 index bc14043752..0000000000 --- a/bluesky/_modules/bluesky/preprocessors.html +++ /dev/null @@ -1,1578 +0,0 @@ - - - - - - - - - - bluesky.preprocessors — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.preprocessors
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.preprocessors

-from __future__ import generator_stop
-
-from collections import OrderedDict, deque, ChainMap
-from collections.abc import Iterable
-import uuid
-from .utils import (normalize_subs_input, root_ancestor,
-                    separate_devices,
-                    Msg, ensure_generator, single_gen,
-                    short_uid as _short_uid, make_decorator,
-                    RunEngineControlException, merge_axis)
-from functools import wraps
-from .plan_stubs import (open_run, close_run, mv, pause, trigger_and_read)
-
-
-
[docs]def plan_mutator(plan, msg_proc): - """ - Alter the contents of a plan on the fly by changing or inserting messages. - - Parameters - ---------- - plan : generator - - a generator that yields messages (`Msg` objects) - msg_proc : callable - This function takes in a message and specifies messages(s) to replace - it with. The function must account for what type of response the - message would prompt. For example, an 'open_run' message causes the - RunEngine to send a uid string back to the plan, while a 'set' message - causes the RunEngine to send a status object back to the plan. The - function should return a pair of generators ``(head, tail)`` that yield - messages. The last message out of the ``head`` generator is the one - whose response will be sent back to the host plan. Therefore, that - message should prompt a response compatible with the message that it is - replacing. Any responses to all other messages will be swallowed. As - shorthand, either ``head`` or ``tail`` can be replaced by ``None``. - This means: - - * ``(None, None)`` No-op. Let the original message pass through. - * ``(head, None)`` Mutate and/or insert messages before the original - message. - * ``(head, tail)`` As above, and additionally insert messages after. - * ``(None, tail)`` Let the original message pass through and then - insert messages after. - - The reason for returning a pair of generators instead of just one is to - provide a way to specify which message's response should be sent out to - the host plan. Again, it's the last message yielded by the first - generator (``head``). - - Yields - ------ - msg : Msg - messages from `plan`, altered by `msg_proc` - - See Also - -------- - :func:`bluesky.plans.msg_mutator` - """ - # internal stacks - msgs_seen = dict() - plan_stack = deque() - result_stack = deque() - tail_cache = dict() - tail_result_cache = dict() - exception = None - - parent_plan = plan - ret_value = None - # seed initial conditions - plan_stack.append(plan) - result_stack.append(None) - - while True: - # get last result - if exception is not None: - # if we have a stashed exception, pass it along - try: - msg = plan_stack[-1].throw(exception) - except StopIteration as e: - # discard the exhausted generator - exhausted_gen = plan_stack.pop() - # if this is the parent plan, capture it's return value - if exhausted_gen is parent_plan: - ret_value = e.value - - # if we just came out of a 'tail' generator, - # discard its return value and replace it with the - # cached one (from the last message in its paired - # 'new_gen') - if id(exhausted_gen) in tail_result_cache: - ret = tail_result_cache.pop(id(exhausted_gen)) - - result_stack.append(ret) - - if id(exhausted_gen) in tail_cache: - gen = tail_cache.pop(id(exhausted_gen)) - if gen is not None: - plan_stack.append(gen) - saved_result = result_stack.pop() - tail_result_cache[id(gen)] = saved_result - # must use None to prime generator - result_stack.append(None) - - if plan_stack: - continue - else: - return ret_value - except Exception as e: - # if we catch an exception, - # the current top plan is dead so pop it - plan_stack.pop() - if plan_stack: - # stash the exception and go to the top - exception = e - continue - else: - raise - else: - exception = None - else: - ret = result_stack.pop() - try: - msg = plan_stack[-1].send(ret) - except StopIteration as e: - # discard the exhausted generator - exhausted_gen = plan_stack.pop() - # if this is the parent plan, capture it's return value - if exhausted_gen is parent_plan: - ret_value = e.value - - # if we just came out of a 'tail' generator, - # discard its return value and replace it with the - # cached one (from the last message in its paired - # 'new_gen') - if id(exhausted_gen) in tail_result_cache: - ret = tail_result_cache.pop(id(exhausted_gen)) - - result_stack.append(ret) - - if id(exhausted_gen) in tail_cache: - gen = tail_cache.pop(id(exhausted_gen)) - if gen is not None: - plan_stack.append(gen) - saved_result = result_stack.pop() - tail_result_cache[id(gen)] = saved_result - # must use None to prime generator - result_stack.append(None) - - if plan_stack: - continue - else: - return ret_value - except Exception as ex: - # we are here because an exception came out of the send - # this may be due to - # a) the plan really raising or - # b) an exception that came out of the run engine via ophyd - - # in either case the current plan is dead so pop it - failed_gen = plan_stack.pop() - if id(failed_gen) in tail_cache: - gen = tail_cache.pop(id(failed_gen)) - if gen is not None: - plan_stack.append(gen) - # if there is at least - if plan_stack: - exception = ex - continue - else: - raise ex - # if inserting / mutating, put new generator on the stack - # and replace the current msg with the first element from the - # new generator - if id(msg) not in msgs_seen: - # Use the id as a hash, and hold a reference to the msg so that - # it cannot be garbage collected until the plan is complete. - msgs_seen[id(msg)] = msg - - new_gen, tail_gen = msg_proc(msg) - # mild correctness check - if tail_gen is not None and new_gen is None: - new_gen = single_gen(msg) - if new_gen is not None: - # stash the new generator - plan_stack.append(new_gen) - # put in a result value to prime it - result_stack.append(None) - # stash the tail generator - tail_cache[id(new_gen)] = tail_gen - # go to the top of the loop - continue - - try: - # yield out the 'current message' and collect the return - inner_ret = yield msg - except GeneratorExit: - # special case GeneratorExit. We must clean up all of our plans - # and exit with out yielding anything else. - for p in plan_stack: - p.close() - raise - except Exception as ex: - if plan_stack: - exception = ex - continue - else: - raise - else: - result_stack.append(inner_ret)
- - -
[docs]def msg_mutator(plan, msg_proc): - """ - A simple preprocessor that mutates or deletes single messages in a plan - - To *insert* messages, use ``plan_mutator`` instead. - - Parameters - ---------- - plan : generator - a generator that yields messages (`Msg` objects) - msg_proc : callable - Expected signature `f(msg) -> new_msg or None` - - Yields - ------ - msg : Msg - messages from `plan`, altered by `msg_proc` - - See Also - -------- - :func:`bluesky.plans.plan_mutator` - """ - ret = None - while True: - try: - msg = plan.send(ret) - msg = msg_proc(msg) - # if None, just skip message - # feed 'None' back down into the base plan, - # this may break some plans - if msg is None: - ret = None - continue - ret = yield msg - except StopIteration as e: - return e.value
- - -
[docs]def pchain(*args): - '''Like `itertools.chain` but using `yield from` - - This ensures than `.send` works as expected and the underlying - plans get the return values - - Parameters - ---------- - args : - generators (plans) - - Yields - ------ - msg : Msg - The messages from each plan in turn - ''' - rets = deque() - for p in args: - rets.append((yield from p)) - return tuple(rets)
- - -def print_summary_wrapper(plan): - """Print summary of plan as it goes by - - Prints a minimal version of the plan, showing only moves and - where events are created. Yields the `Msg` unchanged. - - Parameters - ---------- - plan : iterable - Must yield `Msg` objects - - Yields - ------ - msg : `Msg` - """ - - read_cache = [] - for msg in plan: - cmd = msg.command - if cmd == 'open_run': - print('{:=^80}'.format(' Open Run ')) - elif cmd == 'close_run': - print('{:=^80}'.format(' Close Run ')) - elif cmd == 'set': - print('{motor.name} -> {args[0]}'.format(motor=msg.obj, - args=msg.args)) - elif cmd == 'create': - read_cache = [] - elif cmd == 'read': - read_cache.append(msg.obj.name) - elif cmd == 'save': - print(' Read {}'.format(read_cache)) - yield msg - - -
[docs]def run_wrapper(plan, *, md=None): - """Enclose in 'open_run' and 'close_run' messages. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - md : dict, optional - metadata to be passed into the 'open_run' message - """ - rs_uid = yield from open_run(md) - - def except_plan(e): - if isinstance(e, RunEngineControlException): - yield from close_run(exit_status=e.exit_status) - else: - yield from close_run(exit_status='fail', reason=str(e)) - - yield from contingency_wrapper(plan, - except_plan=except_plan, - else_plan=close_run) - return rs_uid
- - -
[docs]def subs_wrapper(plan, subs): - """ - Subscribe callbacks to the document stream; finally, unsubscribe. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - subs : callable, list of callables, or dict of lists of callables - Documents of each type are routed to a list of functions. - Input is normalized to a dict of lists of functions, like so: - - None -> {'all': [], 'start': [], 'stop': [], 'event': [], - 'descriptor': []} - - func -> {'all': [func], 'start': [], 'stop': [], 'event': [], - 'descriptor': []} - - [f1, f2] -> {'all': [f1, f2], 'start': [], 'stop': [], 'event': [], - 'descriptor': []} - - {'event': [func]} -> {'all': [], 'start': [], 'stop': [], - 'event': [func], 'descriptor': []} - - Signature of functions must conform to `f(name, doc)` where - name is one of {'all', 'start', 'stop', 'event', 'descriptor'} and - doc is a dictionary. - - Yields - ------ - msg : Msg - messages from plan, with 'subscribe' and 'unsubscribe' messages - inserted and appended - """ - subs = normalize_subs_input(subs) - tokens = set() - - def _subscribe(): - for name, funcs in subs.items(): - for func in funcs: - token = yield Msg('subscribe', None, func, name) - tokens.add(token) - - def _unsubscribe(): - for token in tokens: - yield Msg('unsubscribe', None, token=token) - - def _inner_plan(): - yield from _subscribe() - return (yield from plan) - - return (yield from finalize_wrapper(_inner_plan(), - _unsubscribe()))
- - -
[docs]def suspend_wrapper(plan, suspenders): - """ - Install suspenders to the RunEngine, and remove them at the end. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - suspenders : suspender or list of suspenders - Suspenders to use for the duration of the wrapper - - Yields - ------ - msg : Msg - messages from plan, with 'install_suspender' and 'remove_suspender' - messages inserted and appended - """ - if not isinstance(suspenders, Iterable): - suspenders = [suspenders] - - def _install(): - for susp in suspenders: - yield Msg('install_suspender', None, susp) - - def _remove(): - for susp in suspenders: - yield Msg('remove_suspender', None, susp) - - def _inner_plan(): - yield from _install() - return (yield from plan) - - return (yield from finalize_wrapper(_inner_plan(), - _remove()))
- - -def configure_count_time_wrapper(plan, time): - """ - Preprocessor that sets all devices with a `count_time` to the same time. - - The original setting is stashed and restored at the end. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - time : float or None - If None, the plan passes through unchanged. - - Yields - ------ - msg : Msg - messages from plan, with 'set' messages inserted - """ - devices_seen = set() - original_times = {} - - def insert_set(msg): - obj = msg.obj - if obj is not None and obj not in devices_seen: - devices_seen.add(obj) - if hasattr(obj, 'count_time'): - # TODO Do this with a 'read' Msg once reads can be - # marked as belonging to a different event stream (or no - # event stream. - original_times[obj] = obj.count_time.get() - # TODO do this with configure - return pchain(mv(obj.count_time, time), - single_gen(msg)), None - return None, None - - def reset(): - for obj, time in original_times.items(): - yield from mv(obj.count_time, time) - - if time is None: - # no-op - return (yield from plan) - else: - return (yield from finalize_wrapper(plan_mutator(plan, insert_set), - reset())) - - -
[docs]def finalize_wrapper(plan, final_plan, *, pause_for_debug=False): - '''try...finally helper - - Run the first plan and then the second. If any of the messages - raise an error in the RunEngine (or otherwise), the second plan - will attempted to be run anyway. - - See :func:`contingency_wrapper` for a more complex and more - feature-complete error-handling preprocessor. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - final_plan : callable, iterable or iterator - a generator, list, or similar containing `Msg` objects or a callable - that reurns one; attempted to be run no matter what happens in the - first plan - pause_for_debug : bool, optional - If the plan should pause before running the clean final_plan in - the case of an Exception. This is intended as a debugging tool only. - - Yields - ------ - msg : Msg - messages from `plan` until it terminates or an error is raised, then - messages from `final_plan` - - See Also - -------- - :func:`contingency_wrapper` - ''' - # If final_plan is a generator *function* (as opposed to a generator - # *instance*), call it. - if callable(final_plan): - final_plan_instance = final_plan() - else: - final_plan_instance = final_plan - cleanup = True - try: - ret = yield from plan - except GeneratorExit: - cleanup = False - raise - except BaseException: - if pause_for_debug: - yield from pause() - raise - finally: - # if the exception raised in `GeneratorExit` that means - # someone called `gen.close()` on this generator. In those - # cases generators must either re-raise the GeneratorExit or - # raise a different exception. Trying to yield any values - # results in a RuntimeError being raised where `close` is - # called. Thus, we catch, the GeneratorExit, disable cleanup - # and then re-raise - - # https://docs.python.org/3/reference/expressions.html?#generator.close - if cleanup: - yield from ensure_generator(final_plan_instance) - return ret
- - -
[docs]def contingency_wrapper(plan, *, - except_plan=None, - else_plan=None, - final_plan=None, - pause_for_debug=False): - '''try...except...else...finally helper - - See :func:`finalize_wrapper` for a simplified but less powerful - error-handling preprocessor. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - except_plan : generator function, optional - This will be called with the exception as the only input. The - plan does not need to re-raise, but may if you want to change the - exception. - - Only subclasses of `Exception` will be passed in, will not see - `GeneratorExit`, `SystemExit`, or `KeyboardInterrupt` - else_plan : generator function, optional - This will be called with no arguments if plan completes without raising - final_plan : generator function, optional - a generator, list, or similar containing `Msg` objects or a callable - that reurns one; attempted to be run no matter what happens in the - first plan - pause_for_debug : bool, optional - If the plan should pause before running the clean final_plan in - the case of an Exception. This is intended as a debugging tool only. - - Yields - ------ - msg : Msg - messages from `plan` until it terminates or an error is raised, then - messages from `final_plan` - - See Also - -------- - :func:`finalize_wrapper` - ''' - cleanup = True - try: - ret = yield from plan - except GeneratorExit: - cleanup = False - raise - except Exception as e: - if pause_for_debug: - yield from pause() - if except_plan: - # it might be better to throw this in, but this is simpler - # to implement for now - yield from except_plan(e) - raise - else: - if else_plan: - yield from else_plan() - finally: - # if the exception raised in `GeneratorExit` that means - # someone called `gen.close()` on this generator. In those - # cases generators must either re-raise the GeneratorExit or - # raise a different exception. Trying to yield any values - # results in a RuntimeError being raised where `close` is - # called. Thus, we catch, the GeneratorExit, disable cleanup - # and then re-raise - - # https://docs.python.org/3/reference/expressions.html?#generator.close - if cleanup and final_plan: - yield from final_plan() - return ret
- - -
[docs]def finalize_decorator(final_plan): - '''try...finally helper - - Run the first plan and then the second. If any of the messages - raise an error in the RunEngine (or otherwise), the second plan - will attempted to be run anyway. - - Notice that, this decorator requires a generator *function* so that it can - be used multiple times, whereas :func:`bluesky.plans.finalize_wrapper` - accepts either a generator function or a generator instance. - - Parameters - ---------- - final_plan : callable - a callable that returns a generator, list, or similar containing `Msg` - objects; attempted to be run no matter what happens in the first plan - - Yields - ------ - msg : Msg - messages from `plan` until it terminates or an error is raised, then - messages from `final_plan` - ''' - def dec(gen_func): - @wraps(gen_func) - def dec_inner(*inner_args, **inner_kwargs): - if not callable(final_plan): - raise TypeError("final_plan must be a callable (e.g., a " - "generator function) not an iterable (e.g., a " - "generator instance).") - final_plan_instance = final_plan() - plan = gen_func(*inner_args, **inner_kwargs) - cleanup = True - try: - ret = yield from plan - except GeneratorExit: - cleanup = False - raise - finally: - # if the exception raised in `GeneratorExit` that means - # someone called `gen.close()` on this generator. In those - # cases generators must either re-raise the GeneratorExit or - # raise a different exception. Trying to yield any values - # results in a RuntimeError being raised where `close` is - # called. Thus, we catch, the GeneratorExit, disable cleanup - # and then re-raise - - # https://docs.python.org/3/reference/expressions.html?#generator.close - if cleanup: - yield from ensure_generator(final_plan_instance) - return ret - return dec_inner - return dec
- - -def rewindable_wrapper(plan, rewindable): - '''Toggle the 'rewindable' state of the RE - - Allow or disallow rewinding during the processing of the wrapped messages. - Then restore the initial state (rewindable or not rewindable). - - Parameters - ---------- - plan : generator - The plan to wrap in a 'rewindable' or 'not rewindable' context - rewindable : bool - - ''' - initial_rewindable = True - - def capture_rewindable_state(): - nonlocal initial_rewindable - initial_rewindable = yield Msg('rewindable', None, None) - - def set_rewindable(rewindable): - if initial_rewindable != rewindable: - return (yield Msg('rewindable', None, rewindable)) - - def restore_rewindable(): - if initial_rewindable != rewindable: - return (yield Msg('rewindable', None, initial_rewindable)) - - if not rewindable: - yield from capture_rewindable_state() - yield from set_rewindable(rewindable) - return (yield from finalize_wrapper(plan, - restore_rewindable())) - else: - return (yield from plan) - - -
[docs]def inject_md_wrapper(plan, md): - """ - Inject additional metadata into a run. - - This takes precedences over the original metadata dict in the event of - overlapping keys, but it does not mutate the original metadata dict. - (It uses ChainMap.) - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - md : dict - metadata - """ - def _inject_md(msg): - if msg.command == 'open_run': - msg = msg._replace(kwargs=ChainMap(md, msg.kwargs)) - return msg - - return (yield from msg_mutator(plan, _inject_md))
- - -def stub_wrapper(plan): - """ - Remove Msg object in order to use plan as a stub - - This will remove any `open_run`, `close_run`, `stage` and `unstage` `Msg` - objects present in the plan in order for it to be run as part of a larger - scan. Note, that any metadata from the provided plan will not be sent to - the RunEngine automatically. - - Parameters - ---------- - plan : iterable or iterator - A generator list or similar containing `Msg` objects - - Returns - ------- - md : dict - Metadata discovered from `open_run` Msg - """ - md = {} - - def _block_run_control(msg): - """ - Block open and close run messages - """ - # Capture the metadata from open_run - if msg.command == 'open_run': - md.update(msg.kwargs) - return None - elif msg.command in ('close_run', 'stage', 'unstage'): - return None - return msg - - yield from msg_mutator(plan, _block_run_control) - return md - - -
[docs]def monitor_during_wrapper(plan, signals): - """ - Monitor (asynchronously read) devices during runs. - - This is a preprocessor that insert messages immediately after a run is - opened and before it is closed. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - signals : collection - objects that support the Signal interface - - Yields - ------ - msg : Msg - messages from plan with 'monitor', and 'unmontior' messages inserted - - See Also - -------- - :func:`bluesky.plans.fly_during_wrapper` - """ - monitor_msgs = [Msg('monitor', sig, name=sig.name + '_monitor') - for sig in signals] - unmonitor_msgs = [Msg('unmonitor', sig) for sig in signals] - - def insert_after_open(msg): - if msg.command == 'open_run': - def new_gen(): - yield from ensure_generator(monitor_msgs) - return single_gen(msg), new_gen() - else: - return None, None - - def insert_before_close(msg): - if msg.command == 'close_run': - def new_gen(): - yield from ensure_generator(unmonitor_msgs) - yield msg - return new_gen(), None - else: - return None, None - - # Apply nested mutations. - plan1 = plan_mutator(plan, insert_after_open) - plan2 = plan_mutator(plan1, insert_before_close) - return (yield from plan2)
- - -
[docs]def fly_during_wrapper(plan, flyers): - """ - Kickoff and collect "flyer" (asynchronously collect) objects during runs. - - This is a preprocessor that insert messages immediately after a run is - opened and before it is closed. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - flyers : collection - objects that support the flyer interface - - Yields - ------ - msg : Msg - messages from plan with 'kickoff', 'wait' and 'collect' messages - inserted - - See Also - -------- - :func:`bluesky.plans.fly` - """ - grp1 = _short_uid('flyers-kickoff') - grp2 = _short_uid('flyers-complete') - kickoff_msgs = [Msg('kickoff', flyer, group=grp1) for flyer in flyers] - complete_msgs = [Msg('complete', flyer, group=grp2) for flyer in flyers] - collect_msgs = [Msg('collect', flyer) for flyer in flyers] - if flyers: - # If there are any flyers, insert a 'wait' Msg after kickoff, complete - kickoff_msgs += [Msg('wait', None, group=grp1)] - complete_msgs += [Msg('wait', None, group=grp2)] - - def insert_after_open(msg): - if msg.command == 'open_run': - def new_gen(): - yield from ensure_generator(kickoff_msgs) - return single_gen(msg), new_gen() - else: - return None, None - - def insert_before_close(msg): - if msg.command == 'close_run': - def new_gen(): - yield from ensure_generator(complete_msgs) - yield from ensure_generator(collect_msgs) - yield msg - return new_gen(), None - else: - return None, None - - # Apply nested mutations. - plan1 = plan_mutator(plan, insert_after_open) - plan2 = plan_mutator(plan1, insert_before_close) - return (yield from plan2)
- - -
[docs]def lazily_stage_wrapper(plan): - """ - This is a preprocessor that inserts 'stage' messages and appends 'unstage'. - - The first time an object is seen in `plan`, it is staged. To avoid - redundant staging we actually stage the object's ultimate parent. - - At the end, in a `finally` block, an 'unstage' Message issued for every - 'stage' Message. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - - Yields - ------ - msg : Msg - messages from plan with 'stage' messages inserted and 'unstage' - messages appended - """ - COMMANDS = set(['read', 'set', 'trigger', 'kickoff']) - # Cache devices in the order they are staged; then unstage in reverse. - devices_staged = [] - - def inner(msg): - if msg.command in COMMANDS and msg.obj not in devices_staged: - root = root_ancestor(msg.obj) - - def new_gen(): - # Here we insert a 'stage' message - ret = yield Msg('stage', root) - # and cache the result - if ret is None: - # The generator may be being list-ified. - # This is a hack to make that possible. - ret = [root] - devices_staged.extend(ret) - # and then proceed with our regularly scheduled programming - yield msg - return new_gen(), None - else: - return None, None - - def unstage_all(): - for device in reversed(devices_staged): - yield Msg('unstage', device) - - return (yield from finalize_wrapper(plan_mutator(plan, inner), - unstage_all()))
- - -
[docs]def stage_wrapper(plan, devices): - """ - 'Stage' devices (i.e., prepare them for use, 'arm' them) and then unstage. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - devices : collection - list of devices to stage immediately on entrance and unstage on exit - - Yields - ------ - msg : Msg - messages from plan with 'stage' and finally 'unstage' messages inserted - - See Also - -------- - :func:`bluesky.plans.lazily_stage_wrapper` - :func:`bluesky.plans.stage` - :func:`bluesky.plans.unstage` - """ - devices = separate_devices(root_ancestor(device) for device in devices) - - def stage_devices(): - for d in devices: - yield Msg('stage', d) - - def unstage_devices(): - for d in reversed(devices): - yield Msg('unstage', d) - - def inner(): - yield from stage_devices() - return (yield from plan) - - return (yield from finalize_wrapper(inner(), unstage_devices()))
- - -def _normalize_devices(devices): - coupled_parents = set() - # if we have any pseudo devices then setting any part of it - # needs to trigger the relative behavior. - io, co, go = merge_axis(devices) - devices = set(devices) | set(io) | set(co) | set(go) - # if a device with coupled children is directly in the - # list, include all the coupled children as well - for obj in co: - devices |= set(obj.pseudo_positioners) - coupled_parents.add(obj) - - # if at least one child of a device with coupled children - # only include the coupled children if at least of the children - # directly included is one of the coupled ones. - for obj, type_map in go.items(): - if len(type_map['pseudo']) > 0: - devices |= set(obj.pseudo_positioners) - coupled_parents.add(obj) - return devices, coupled_parents - - -def __read_and_stash_a_motor(obj, initial_positions, coupled_parents): - """Internal plan for relative set and reset wrappers - - - .. warning :: - - Do not use this plan directly for any reason. - - """ - # obj should have a `position` attribution - try: - cur_pos = obj.position - except AttributeError: - # ... but as a fallback we can read obj and grab the value of the - # first key - reading = yield Msg('read', obj) - if reading is None: - # this plan may be being list-ified - print("*** all positions for {m.name} are " - "relative to current position ***".format(m=obj)) - cur_pos = 0 - else: - fields = getattr(obj, 'hints', {}).get('fields', []) - if len(fields) == 1: - k, = fields - cur_pos = reading[k]['value'] - elif len(fields) == 0: - k = list(reading.keys())[0] - cur_pos = reading[k]['value'] - else: - raise Exception("do not yet know how to deal with " - "non pseudopositioner multi-axis. Please " - "contact DAMA to justify why you need " - "this.") - - initial_positions[obj] = cur_pos - - # if we move a pseudo positioner also stash it's children - if obj in coupled_parents: - for c, p in zip(obj.pseudo_positioners, cur_pos): - initial_positions[c] = p - - # if we move a pseudo single, also stash it's parent and siblings - parent = obj.parent - if parent in coupled_parents and obj in parent.pseudo_positioners: - parent_pos = parent.position - initial_positions[parent] = parent_pos - for c, p in zip(parent.pseudo_positioners, parent_pos): - initial_positions[c] = p - - # TODO forbid mixed pseudo / real motion - - -
[docs]def relative_set_wrapper(plan, devices=None): - """ - Interpret 'set' messages on devices as relative to initial position. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - devices : collection or None, optional - if default (None), apply to all devices that are moved by the plan - - Yields - ------ - msg : Msg - messages from plan, with 'read' messages inserted and 'set' messages - mutated - """ - initial_positions = {} - if devices is not None: - devices, coupled_parents = _normalize_devices(devices) - else: - coupled_parents = set() - - def rewrite_pos(msg): - if (msg.command == 'set') and (msg.obj in initial_positions): - rel_pos, = msg.args - abs_pos = initial_positions[msg.obj] + rel_pos - new_msg = msg._replace(args=(abs_pos,)) - return new_msg - else: - return msg - - def insert_reads(msg): - eligible = (devices is None) or (msg.obj in devices) - seen = msg.obj in initial_positions - if (msg.command == 'set') and eligible and not seen: - return (pchain( - __read_and_stash_a_motor( - msg.obj, initial_positions, coupled_parents), - single_gen(msg)), None) - else: - return None, None - - plan = plan_mutator(plan, insert_reads) - plan = msg_mutator(plan, rewrite_pos) - return (yield from plan)
- - -
[docs]def reset_positions_wrapper(plan, devices=None): - """ - Return movable devices to their initial positions at the end. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - devices : collection or None, optional - If default (None), apply to all devices that are moved by the plan. - - Yields - ------ - msg : Msg - messages from plan with 'read' and finally 'set' messages inserted - """ - initial_positions = OrderedDict() - if devices is not None: - devices, coupled_parents = _normalize_devices(devices) - else: - coupled_parents = set() - - def insert_reads(msg): - eligible = devices is None or msg.obj in devices - seen = msg.obj in initial_positions - if (msg.command == 'set') and eligible and not seen: - return (pchain( - __read_and_stash_a_motor( - msg.obj, initial_positions, coupled_parents), - single_gen(msg)), None) - else: - return None, None - - def reset(): - blk_grp = 'reset-{}'.format(str(uuid.uuid4())[:6]) - for k, v in initial_positions.items(): - if k.parent in coupled_parents: - continue - yield Msg('set', k, v, group=blk_grp) - yield Msg('wait', None, group=blk_grp) - - return (yield from finalize_wrapper(plan_mutator(plan, insert_reads), - reset()))
- - -
[docs]def baseline_wrapper(plan, devices, name='baseline'): - """ - Preprocessor that records a baseline of all `devices` after `open_run` - - The readings are designated for a separate event stream named 'baseline' by - default. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - devices : collection - collection of Devices to read - If None, the plan passes through unchanged. - name : string, optional - name for event stream; by default, 'baseline' - - Yields - ------ - msg : Msg - messages from plan, with 'set' messages inserted - """ - def insert_baseline(msg): - if msg.command == 'open_run': - return None, trigger_and_read(devices, name=name) - - elif msg.command == 'close_run': - def post_baseline(): - yield from trigger_and_read(devices, name=name) - return (yield msg) - - return post_baseline(), None - - return None, None - - if not devices: - # no-op - return (yield from plan) - else: - return (yield from plan_mutator(plan, insert_baseline))
- - -# Make generator function decorator for each generator instance wrapper. -baseline_decorator = make_decorator(baseline_wrapper) -subs_decorator = make_decorator(subs_wrapper) -suspend_decorator = make_decorator(suspend_wrapper) -relative_set_decorator = make_decorator(relative_set_wrapper) -reset_positions_decorator = make_decorator(reset_positions_wrapper) -# finalize_decorator is custom-made since it takes a plan as its -# argument. See its docstring for details why. -lazily_stage_decorator = make_decorator(lazily_stage_wrapper) -stage_decorator = make_decorator(stage_wrapper) -fly_during_decorator = make_decorator(fly_during_wrapper) -monitor_during_decorator = make_decorator(monitor_during_wrapper) -inject_md_decorator = make_decorator(inject_md_wrapper) -run_decorator = make_decorator(run_wrapper) -contingency_decorator = make_decorator(contingency_wrapper) -stub_decorator = make_decorator(stub_wrapper) -configure_count_time_decorator = make_decorator(configure_count_time_wrapper) - - -
[docs]class SupplementalData: - """ - A configurable preprocessor for supplemental measurements - - This is a plan preprocessor. It inserts messages into plans to: - - * take "baseline" readings at the beginning and end of each run for the - devices listed in its ``baseline`` atrribute - * monitor signals in its ``monitors`` attribute for asynchronous - updates during each run. - * kick off "flyable" devices listed in its ``flyers`` attribute at the - beginning of each run and collect their data at the end - - Internally, it uses the plan preprocessors: - - * :func:`baseline_wrapper` - * :func:`monitor_during_wrapper` - * :func:`fly_during_wrapper` - - Parameters - ---------- - baseline : list - Devices to be read at the beginning and end of each run - monitors : list - Signals (not multi-signal Devices) to be monitored during each run, - generating readings asynchronously - flyers : list - "Flyable" Devices to be kicked off before each run and collected - at the end of each run - - Examples - -------- - Create an instance of SupplementalData and apply it to a RunEngine. - - >>> sd = SupplementalData(baseline=[some_motor, some_detector]), - ... monitors=[some_signal], - ... flyers=[some_flyer]) - >>> RE = RunEngine({}) - >>> RE.preprocessors.append(sd) - - Now all plans executed by RE will be modified to add baseline readings - (before and after each run), monitors (during each run), and flyers - (kicked off before each run and collected afterward). - - Inspect or update the lists of devices interactively. - - >>> sd.baseline - [some_motor, some_detector] - - >>> sd.baseline.remove(some_motor) - - >>> sd.baseline - [some_detector] - - >>> sd.baseline.append(another_detector) - - >>> sd.baseline - [some_detector, another_detector] - - Each attribute (``baseline``, ``monitors``, ``flyers``) is an ordinary - Python list, support all the standard list methods, such as: - - >>> sd.baseline.clear() - - The arguments to SupplementalData are optional. All the lists - will empty by default. As shown above, they can be populated - interactively. - - >>> sd = SupplementalData() - >>> RE = RunEngine({}) - >>> RE.preprocessors.append(sd) - >>> sd.baseline.append(some_detector) - """ - def __init__(self, *, baseline=None, monitors=None, flyers=None): - if baseline is None: - baseline = [] - if monitors is None: - monitors = [] - if flyers is None: - flyers = [] - self.baseline = list(baseline) - self.monitors = list(monitors) - self.flyers = list(flyers) - - def __repr__(self): - return ("{cls}(baseline={baseline}, monitors={monitors}, " - "flyers={flyers})" - "").format(cls=type(self).__name__, **vars(self)) - - # I'm not sure why anyone would want to pickle this but it's good manners - # to avoid breaking pickling. - - def __setstate__(self, state): - baseline, monitors, flyers = state - self.baseline = baseline - self.monitors = monitors - self.flyers = flyers - - def __getstate__(self): - return (self.baseline, self.monitors, self.flyers) - - def __call__(self, plan): - """ - Insert messages into a plan. - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - """ - # Read this as going from the inside out: first we wrap the plan in the - # flying instructions, then monitoring, then baseline, so that the - # order of operations is: - # - Take baseline readings - # - Start monitoring. - # - Kick off flyers and wait for them to be kicked off. - # - Do `plan`. - # - Complete and collect flyers. - # - Stop monitoring. - # - Take baseline readings. - plan = fly_during_wrapper(plan, self.flyers) - plan = monitor_during_wrapper(plan, self.monitors) - plan = baseline_wrapper(plan, self.baseline) - return (yield from plan)
- - -def set_run_key_wrapper(plan, run): - """ - Add a run key to each message in wrapped plan - - Parameters - ---------- - plan : iterable or iterator - a generator, list, or similar containing `Msg` objects - run : str or any other type except None - The run key to set on each Msg. It is recommended that run key represents - informative string for better readability of plans. But value of any other - type can be used if needed. - """ - if run is None: - raise ValueError("run ID can not be None") - - def _set_run_key(msg): - # Replace only the default value None - if msg.run is None: - msg = msg._replace(run=run) - return msg - - return (yield from msg_mutator(plan, _set_run_key)) - - -set_run_key_decorator = make_decorator(set_run_key_wrapper) -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/run_engine.html b/bluesky/_modules/bluesky/run_engine.html deleted file mode 100644 index bb9de03935..0000000000 --- a/bluesky/_modules/bluesky/run_engine.html +++ /dev/null @@ -1,2698 +0,0 @@ - - - - - - - - - - bluesky.run_engine — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.run_engine
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.run_engine

-import asyncio
-from datetime import datetime
-import sys
-from warnings import warn
-from inspect import Parameter, Signature
-from itertools import count
-from collections import deque, defaultdict, ChainMap
-from enum import Enum
-import functools
-import inspect
-from contextlib import ExitStack
-import threading
-import weakref
-from .bundlers import RunBundler
-
-import concurrent
-
-from event_model import DocumentNames, schema_validators
-from .log import logger, msg_logger, state_logger, ComposableLogAdapter
-from super_state_machine.machines import StateMachine
-from super_state_machine.extras import PropertyMachine
-from super_state_machine.errors import TransitionError
-
-try:
-    from asyncio import current_task
-except ImportError:
-    # handle py < 3,7
-    from asyncio.tasks import Task
-    current_task = Task.current_task
-    del Task
-
-from .utils import (CallbackRegistry, SigintHandler,
-                    normalize_subs_input, AsyncInput,
-                    NoReplayAllowed, RequestAbort, RequestStop,
-                    RunEngineInterrupted, IllegalMessageSequence,
-                    FailedPause, FailedStatus, InvalidCommand,
-                    PlanHalt, Msg, ensure_generator, single_gen,
-                    DefaultDuringTask)
-
-
-class _RunEnginePanic(Exception):
-    ...
-
-
-class RunEngineStateMachine(StateMachine):
-    """
-
-    Attributes
-    ----------
-    is_idle
-        State machine is in its idle state
-    is_running
-        State machine is in its running state
-    is_paused
-        State machine is paused.
-    """
-
-    class States(Enum):
-        """state.name = state.value"""
-        IDLE = 'idle'
-
-        RUNNING = 'running'
-
-        PAUSING = 'pausing'
-        PAUSED = 'paused'
-
-        HALTING = 'halting'
-        STOPPING = 'stopping'
-        ABORTING = 'aborting'
-
-        SUSPENDING = 'suspending'
-
-        PANICKED = 'panicked'
-
-        @classmethod
-        def states(cls):
-            return [state.value for state in cls]
-
-    class Meta:
-        allow_empty = False
-        initial_state = 'idle'
-        transitions = {
-            # Notice that 'transitions' and 'named_transitions' have
-            # opposite to <--> from structure.
-            # from_state : [valid_to_states]
-            'idle': ['running', 'panicked'],
-            'running': ['idle', 'pausing', 'halting', 'stopping',
-                        'aborting', 'suspending', 'panicked'],
-            'pausing': ['paused', 'idle', 'halting', 'aborting', 'panicked'],
-            'suspending': ['running', 'halting', 'aborting', 'panicked'],
-            'paused': ['idle', 'running', 'halting', 'stopping', 'aborting',
-                       'panicked'],
-            'halting': ['idle', 'panicked'],
-            'stopping': ['idle', 'panicked'],
-            'aborting': ['idle', 'panicked'],
-            'panicked': []
-        }
-        named_checkers = [
-            ('can_pause', 'paused'),
-        ]
-
-
-class LoggingPropertyMachine(PropertyMachine):
-    """expects object to have a `log` attribute
-    and a `state_hook` attribute that is ``None`` or a callable with signature
-    ``f(value, old_value)``"""
-    def __init__(self, machine_type):
-        super().__init__(machine_type)
-
-    def __set__(self, obj, value):
-        own = type(obj)
-        old_value = self.__get__(obj, own)
-        with obj._state_lock:
-            super().__set__(obj, value)
-        value = self.__get__(obj, own)
-        tags = {'old_state': old_value,
-                'new_state': value,
-                'RE': self}
-
-        state_logger.info("Change state on %r from %r -> %r",
-                          obj, old_value, value, extra=tags)
-        if obj.state_hook is not None:
-            obj.state_hook(value, old_value)
-
-    def __get__(self, instance, owner):
-        if instance is None:
-            return super().__get__(instance, owner)
-        with instance._state_lock:
-            return super().__get__(instance, owner)
-
-
-# See RunEngine.__call__.
-_call_sig = Signature(
-    [Parameter('self', Parameter.POSITIONAL_ONLY),
-     Parameter('plan', Parameter.POSITIONAL_ONLY),
-     Parameter('subs', Parameter.POSITIONAL_ONLY, default=None),
-     Parameter('metadata_kw', Parameter.VAR_KEYWORD)])
-
-
-def default_scan_id_source(md):
-    return md.get('scan_id', 0) + 1
-
-
-def _state_locked(func):
-    @functools.wraps(func)
-    def inner(self, *args, **kwargs):
-        with self._state_lock:
-            return func(self, *args, **kwargs)
-
-    return inner
-
-
-
[docs]class RunEngine: - """The Run Engine execute messages and emits Documents. - - Parameters - ---------- - md : dict-like, optional - The default is a standard Python dictionary, but fancier - objects can be used to store long-term history and persist - it between sessions. The standard configuration - instantiates a Run Engine with historydict.HistoryDict, a - simple interface to a sqlite file. Any object supporting - `__getitem__`, `__setitem__`, and `clear` will work. - - loop : asyncio event loop - e.g., ``asyncio.get_event_loop()`` or ``asyncio.new_event_loop()`` - - preprocessors : list, optional - Generator functions that take in a plan (generator instance) and - modify its messages on the way out. Suitable examples include - the functions in the module ``bluesky.plans`` with names ending in - 'wrapper'. Functions are composed in order: the preprocessors - ``[f, g]`` are applied like ``f(g(plan))``. - - context_managers : list, optional - Context managers that will be entered when we run a plan. The context - managers will be composed in order, much like the preprocessors. If - this argument is omitted, we will use a user-oriented handler for - SIGINT. The elements of this list will be passed this ``RunEngine`` - instance as their only argument. You may pass an empty list if you - would like a ``RunEngine`` with no signal handling and no context - managers. - - md_validator : callable, optional - a function that raises and prevents starting a run if it deems - the metadata to be invalid or incomplete - Expected signature: f(md) - Function should raise if md is invalid. What that means is - completely up to the user. The function's return value is - ignored. - - scan_id_source : callable, optional - a function that will be used to calculate scan_id. Default is to - increment scan_id by 1 each time. However you could pass in a - customized function to get a scan_id from any source. - Expected signature: f(md) - Expected return: updated scan_id value - - during_task : reference to an object of class DuringTask, optional - Class methods: ``block()`` to be run to block - the main thread during `RE.__call__` - - The required signatures for the class methods :: - - def block(ev: Threading.Event) -> None: - "Returns when ev is set" - - The default value handles the cases of: - - Matplotlib is not imported (just wait on the event) - - Matplotlib is imported, but not using a Qt, notebook or ipympl - backend (just wait on the event) - - Matplotlib is imported and using a Qt backend (run the Qt app - on the main thread until the run finishes) - - Matplotlib is imported and using a nbagg or ipympl backend ( - wait on the event and poll to push updates to the browser) - - Attributes - ---------- - md - Direct access to the dict-like persistent storage described above - - record_interruptions - False by default. Set to True to generate an extra event stream - that records any interruptions (pauses, suspensions). - - state - {'idle', 'running', 'paused'} - - suspenders - Read-only collection of `bluesky.suspenders.SuspenderBase` objects - which can suspend and resume execution; see related methods. - - preprocessors : list - Generator functions that take in a plan (generator instance) and - modify its messages on the way out. Suitable examples include - the functions in the module ``bluesky.plans`` with names ending in - 'wrapper'. Functions are composed in order: the preprocessors - ``[f, g]`` are applied like ``f(g(plan))``. - - msg_hook - Callable that receives all messages before they are processed - (useful for logging or other development purposes); expected - signature is ``f(msg)`` where ``msg`` is a ``bluesky.Msg``, a - kind of namedtuple; default is None. - - state_hook - Callable with signature ``f(new_state, old_state)`` that will be - called whenever the RunEngine's state attribute is updated; default - is None - - waiting_hook - Callable with signature ``f(status_object)`` that will be called - whenever the RunEngine is waiting for long-running commands - (trigger, set, kickoff, complete) to complete. This hook is useful to - incorporate a progress bar. - - ignore_callback_exceptions - Boolean, False by default. - - loop : asyncio event loop - e.g., ``asyncio.get_event_loop()`` or ``asyncio.new_event_loop()`` - - max_depth - Maximum stack depth; set this to prevent users from calling the - RunEngine inside a function (which can result in unexpected - behavior and breaks introspection tools). Default is None. - For built-in Python interpreter, set to 2. For IPython, set to 11 - (tested on IPython 5.1.0; other versions may vary). - - pause_msg : str - The message printed when a run is interrupted. This message - includes instructions of changing the state of the RunEngine. - It is set to ``bluesky.run_engine.PAUSE_MSG`` by default and - can be modified based on needs. - - commands: - The list of commands available to Msg. - - """ - - _state = LoggingPropertyMachine(RunEngineStateMachine) - _UNCACHEABLE_COMMANDS = ['pause', 'subscribe', 'unsubscribe', 'stage', - 'unstage', 'monitor', 'unmonitor', 'open_run', - 'close_run', 'install_suspender', - 'remove_suspender'] - - @property - def state(self): - return self._state - -
[docs] def __init__(self, md=None, *, loop=None, preprocessors=None, - context_managers=None, md_validator=None, - scan_id_source=default_scan_id_source, - during_task=None): - if loop is None: - loop = get_bluesky_event_loop() - self._th = _ensure_event_loop_running(loop) - self._state_lock = threading.RLock() - self._loop = loop - if sys.version_info < (3, 8): - self._loop_for_kwargs = self._loop - else: - self._loop_for_kwargs = None - # When set, RunEngine.__call__ should stop blocking. - self._blocking_event = threading.Event() - - # When cleared, RunEngine._run will pause until set. - self._run_permit = None - - setup_event = threading.Event() - - def setup_run_permit(): - self._run_permit = asyncio.Event(loop=self._loop_for_kwargs) - self._run_permit.set() - setup_event.set() - - self.loop.call_soon_threadsafe(setup_run_permit) - setup_event.wait() - - # Make a logger for this specific RE instance, using the instance's - # Python id, to keep from mixing output from separate instances. - self.log = ComposableLogAdapter(logger, {'RE': self}) - - if md is None: - md = {} - self.md = md - self.md.setdefault('versions', {}) - - try: - import ophyd - self.md['versions']['ophyd'] = ophyd.__version__ - except ImportError: - self.log.debug("Failed to import ophyd.") - - from ._version import get_versions - self.md['versions']['bluesky'] = get_versions()['version'] - del get_versions - - if preprocessors is None: - preprocessors = [] - self.preprocessors = preprocessors - if context_managers is None: - context_managers = [SigintHandler] - self.context_managers = context_managers - if md_validator is None: - md_validator = _default_md_validator - self.md_validator = md_validator - self.scan_id_source = scan_id_source - - self.max_depth = None - self.msg_hook = None - self.state_hook = None - self.waiting_hook = None - self.record_interruptions = False - self.pause_msg = PAUSE_MSG - - if during_task is None: - during_task = DefaultDuringTask() - self._during_task = during_task - - # The RunEngine keeps track of a *lot* of state. - # All flags and caches are defined here with a comment. Good luck. - - self._run_bundlers = {} # a mapping of open run -> bundlers - self._metadata_per_call = {} # for all runs generated by one __call__ - self._deferred_pause_requested = False # pause at next 'checkpoint' - self._exception = None # stored and then raised in the _run loop - self._interrupted = False # True if paused, aborted, or failed - self._staged = set() # objects staged, not yet unstaged - self._objs_seen = set() # all objects seen - self._movable_objs_touched = set() # objects we moved at any point - self._run_start_uids = list() # run start uids generated by __call__ - self._suspenders = set() # set holding suspenders - self._groups = defaultdict(set) # sets of Events to wait for - self._status_objs = defaultdict(set) # status objects to wait for - self._temp_callback_ids = set() # ids from CallbackRegistry - self._msg_cache = deque() # history of processed msgs for rewinding - self._rewindable_flag = True # if the RE is allowed to replay msgs - self._plan_stack = deque() # stack of generators to work off of - self._response_stack = deque() # resps to send into the plans - self._exit_status = 'success' # optimistic default - self._reason = '' # reason for abort - self._task = None # asyncio.Task associated with call to self._run - self._task_fut = None # future proxy to the task above - self._status_tasks = deque() # from self._status_object_completed - self._pardon_failures = None # will hold an asyncio.Event - self._plan = None # the plan instance from __call__ - self._command_registry = { - 'create': self._create, - 'save': self._save, - 'drop': self._drop, - 'read': self._read, - 'monitor': self._monitor, - 'unmonitor': self._unmonitor, - 'null': self._null, - 'RE_class': self._RE_class, - 'stop': self._stop, - 'set': self._set, - 'trigger': self._trigger, - 'sleep': self._sleep, - 'wait': self._wait, - 'checkpoint': self._checkpoint, - 'clear_checkpoint': self._clear_checkpoint, - 'rewindable': self._rewindable, - 'pause': self._pause, - 'resume': self._resume, - 'collect': self._collect, - 'kickoff': self._kickoff, - 'complete': self._complete, - 'configure': self._configure, - 'stage': self._stage, - 'unstage': self._unstage, - 'subscribe': self._subscribe, - 'unsubscribe': self._unsubscribe, - 'open_run': self._open_run, - 'close_run': self._close_run, - 'wait_for': self._wait_for, - 'input': self._input, - 'install_suspender': self._install_suspender, - 'remove_suspender': self._remove_suspender, } - - # public dispatcher for callbacks - # The Dispatcher's public methods are exposed through the - # RunEngine for user convenience. - self.dispatcher = Dispatcher() - self.ignore_callback_exceptions = False - - # aliases for back-compatibility - self.subscribe_lossless = self.dispatcher.subscribe - self.unsubscribe_lossless = self.dispatcher.unsubscribe - self._subscribe_lossless = self.dispatcher.subscribe - self._unsubscribe_lossless = self.dispatcher.unsubscribe
- - @property - def commands(self): - ''' - The list of commands available to Msg. - - See Also - -------- - :meth:`RunEngine.register_command` - :meth:`RunEngine.unregister_command` - :meth:`RunEngine.print_command_registry` - - Examples - -------- - >>> from bluesky import RunEngine - >>> RE = RunEngine() - >>> # to list commands - >>> RE.commands - ''' - # return as a list, not lazy loader, no surprises... - return list(self._command_registry.keys()) - -
[docs] def print_command_registry(self, verbose=False): - ''' - This conveniently prints the command registry of available - commands. - - Parameters - ---------- - Verbose : bool, optional - verbose print. Default is False - - See Also - -------- - :meth:`RunEngine.register_command` - :meth:`RunEngine.unregister_command` - :attr:`RunEngine.commands` - - Examples - -------- - >>> from bluesky import RunEngine - >>> RE = RunEngine() - >>> # Print a very verbose list of currently registered commands - >>> RE.print_command_registry(verbose=True) - ''' - commands = "List of available commands\n" - - for command, func in self._command_registry.items(): - docstring = func.__doc__ - if not verbose: - docstring = docstring.split("\n")[0] - commands = commands + "{} : {}\n".format(command, docstring) - - return commands
- -
[docs] def subscribe(self, func, name='all'): - """ - Register a callback function to consume documents. - - .. versionchanged :: 0.10.0 - The order of the arguments was swapped and the ``name`` - argument has been given a default value, ``'all'``. Because the - meaning of the arguments is unambiguous (they must be a callable - and a string, respectively) the old order will be supported - indefinitely, with a warning. - - Parameters - ---------- - func: callable - expecting signature like ``f(name, document)`` - where name is a string and document is a dict - name : {'all', 'start', 'descriptor', 'event', 'stop'}, optional - the type of document this function should receive ('all' by - default) - - Returns - ------- - token : int - an integer ID that can be used to unsubscribe - - See Also - -------- - :meth:`RunEngine.unsubscribe` - """ - # pass through to the Dispatcher, spelled out verbosely here to make - # sphinx happy -- tricks with __doc__ aren't enough to fool it - return self.dispatcher.subscribe(func, name)
- -
[docs] def unsubscribe(self, token): - """ - Unregister a callback function its integer ID. - - Parameters - ---------- - token : int - the integer ID issued by :meth:`RunEngine.subscribe` - - See Also - -------- - :meth:`RunEngine.subscribe` - """ - # pass through to the Dispatcher, spelled out verbosely here to make - # sphinx happy -- tricks with __doc__ aren't enough to fool it - return self.dispatcher.unsubscribe(token)
- - @property - def rewindable(self): - return self._rewindable_flag - - @rewindable.setter - def rewindable(self, v): - cur_state = self._rewindable_flag - self._rewindable_flag = bool(v) - if self.resumable and self._rewindable_flag != cur_state: - self._reset_checkpoint_state() - - @property - def loop(self): - return self._loop - - @property - def suspenders(self): - return tuple(self._suspenders) - - @property - def verbose(self): - return not self.log.disabled - - @verbose.setter - def verbose(self, value): - self.log.disabled = not value - - def _clear_run_cache(self): - "Clean up for a new run." - self._groups.clear() - self._status_objs.clear() - self._interruptions_desc_uid = None - self._interruptions_counter = count(1) - - @_state_locked - def _clear_call_cache(self): - "Clean up for a new __call__ (which may encompass multiple runs)." - self._metadata_per_call.clear() - self._staged.clear() - self._objs_seen.clear() - self._movable_objs_touched.clear() - self._deferred_pause_requested = False - self._plan_stack = deque() - self._msg_cache = deque() - self._response_stack = deque() - self._exception = None - self._run_start_uids.clear() - self._exit_status = 'success' - self._reason = '' - self._task = None - self._task_fut = None - self._status_tasks.clear() - self._pardon_failures = asyncio.Event(loop=self._loop_for_kwargs) - self._plan = None - self._interrupted = False - - # Unsubscribe for per-run callbacks. - for cid in self._temp_callback_ids: - self.unsubscribe(cid) - self._temp_callback_ids.clear() - - def reset(self): - """ - Clean up caches and unsubscribe subscriptions. - - Lossless subscriptions are not unsubscribed. - """ - if self._state != 'idle': - self.halt() - self._clear_run_cache() - self._clear_call_cache() - self.dispatcher.unsubscribe_all() - - @property - def resumable(self): - "i.e., can the plan in progress by rewound" - return self._msg_cache is not None - - @property - def ignore_callback_exceptions(self): - return self.dispatcher.ignore_exceptions - - @ignore_callback_exceptions.setter - def ignore_callback_exceptions(self, val): - self.dispatcher.ignore_exceptions = val - -
[docs] def register_command(self, name, func): - """ - Register a new Message command. - - Parameters - ---------- - name : str - func : callable - This can be a function or a method. The signature is `f(msg)`. - - See Also - -------- - :meth:`RunEngine.unregister_command` - :meth:`RunEngine.print_command_registry` - :attr:`RunEngine.commands` - """ - self._command_registry[name] = func
- -
[docs] def unregister_command(self, name): - """ - Unregister a Message command. - - Parameters - ---------- - name : str - - See Also - -------- - :meth:`RunEngine.register_command` - :meth:`RunEngine.print_command_registry` - :attr:`RunEngine.commands` - """ - del self._command_registry[name]
- -
[docs] def request_pause(self, defer=False): - """ - Command the Run Engine to pause. - - This function is called by 'pause' Messages. It can also be called - by other threads. It cannot be called on the main thread during a run, - but it is called by SIGINT (i.e., Ctrl+C). - - If there current run has no checkpoint (via the 'clear_checkpoint' - message), this will cause the run to abort. - - Parameters - ---------- - defer : bool, optional - If False, pause immediately before processing any new messages. - If True, pause at the next checkpoint. - False by default. - """ - future = asyncio.run_coroutine_threadsafe( - self._request_pause_coro(defer), - loop=self.loop) - # TODO add a timeout here? - return future.result()
- - async def _request_pause_coro(self, defer=False): - # We are pausing. Cancel any deferred pause previously requested. - if defer: - self._deferred_pause_requested = True - print("Deferred pause acknowledged. Continuing to checkpoint.") - return - - print("Pausing...") - - self._deferred_pause_requested = False - self._interrupted = True - self._state = 'pausing' - for current_run in self._run_bundlers.values(): - current_run.record_interruption('pause') - - self._task.cancel() - -
[docs] def __call__(self, *args, **metadata_kw): - """Execute a plan. - - Any keyword arguments will be interpreted as metadata and recorded with - any run(s) created by executing the plan. Notice that the plan - (required) and extra subscriptions (optional) must be given as - positional arguments. - - Parameters - ---------- - plan : generator (positional only) - a generator or that yields ``Msg`` objects (or an iterable that - returns such a generator) - subs : callable, list, or dict, optional (positional only) - Temporary subscriptions (a.k.a. callbacks) to be used on this run. - For convenience, any of the following are accepted: - - * a callable, which will be subscribed to 'all' - * a list of callables, which again will be subscribed to 'all' - * a dictionary, mapping specific subscriptions to callables or - lists of callables; valid keys are {'all', 'start', 'stop', - 'event', 'descriptor'} - - Returns - ------- - uids : list - list of uids (i.e. RunStart Document uids) of run(s) - """ - if self.state == 'panicked': - raise RuntimeError("The RunEngine is panicked and " - "cannot be recovered. " - "You must restart bluesky.") - # This scheme lets us make 'plan' and 'subs' POSITIONAL ONLY, reserving - # all keyword arguments for user metdata. - arguments = _call_sig.bind(self, *args, **metadata_kw).arguments - plan = arguments['plan'] - subs = arguments.get('subs', None) - metadata_kw = arguments.get('metadata_kw', {}) - if 'raise_if_interrupted' in metadata_kw: - warn("The 'raise_if_interrupted' flag has been removed. The " - "RunEngine now always raises RunEngineInterrupted if it is " - "interrupted. The 'raise_if_interrupted' keyword argument, " - "like all keyword arguments, will be interpreted as " - "metadata.") - # Check that the RE is not being called from inside a function. - if self.max_depth is not None: - frame = inspect.currentframe() - depth = len(inspect.getouterframes(frame)) - if depth > self.max_depth: - text = MAX_DEPTH_EXCEEDED_ERR_MSG.format(self.max_depth, depth) - raise RuntimeError(text) - - # If we are in the wrong state, raise. - if not self._state.is_idle: - raise RuntimeError("The RunEngine is in a %s state" % self._state) - - futs = [] - tripped_justifications = [] - for sup in self.suspenders: - f_lst, justification = sup.get_futures() - if f_lst: - futs.extend(f_lst) - tripped_justifications.append(justification) - - if tripped_justifications: - print("At least one suspender has tripped. The plan will begin " - "when all suspenders are ready. Justification:") - for i, justification in enumerate(tripped_justifications): - print(' {}. {}'.format(i + 1, justification)) - - print() - print("Suspending... To get to the prompt, " - "hit Ctrl-C twice to pause.") - - self._clear_call_cache() - self._clear_run_cache() # paranoia, in case of previous bad exit - - for name, funcs in normalize_subs_input(subs).items(): - for func in funcs: - self._temp_callback_ids.add(self.subscribe(func, name)) - - self._plan = plan # this ref is just used for metadata introspection - self._metadata_per_call.update(metadata_kw) - - gen = ensure_generator(plan) - for wrapper_func in self.preprocessors: - gen = wrapper_func(gen) - - self._plan_stack.append(gen) - self._response_stack.append(None) - if futs: - self._plan_stack.append(single_gen(Msg('wait_for', None, futs))) - self._response_stack.append(None) - self.log.info("Executing plan %r", self._plan) - - def _build_task(): - # make sure _run will block at the top - self._run_permit.clear() - self._blocking_event.clear() - self._task_fut = asyncio.run_coroutine_threadsafe(self._run(), - loop=self.loop) - - def set_blocking_event(future): - self._blocking_event.set() - - self._task_fut.add_done_callback(set_blocking_event) - - self._resume_task(init_func=_build_task) - - if self._interrupted: - raise RunEngineInterrupted(self.pause_msg) from None - - return tuple(self._run_start_uids)
- - __call__.__signature__ = _call_sig - -
[docs] def resume(self): - """Resume a paused plan from the last checkpoint. - - Returns - ------- - uids : list - list of Header uids (a.k.a RunStart uids) of run(s) - """ - if self.state == 'panicked': - raise RuntimeError("The RunEngine is panicked and " - "cannot be recovered. " - "You must restart bluesky.") - - # The state machine does not capture the whole picture. - if not self._state.is_paused: - raise TransitionError("The RunEngine is the {0} state. " - "You can only resume for the paused state." - "".format(self._state)) - - self._interrupted = False - for current_run in self._run_bundlers.values(): - current_run.record_interruption('resume') - new_plan = self._rewind() - self._plan_stack.append(new_plan) - self._response_stack.append(None) - # Notify Devices of the resume in case they want to clean up. - for obj in self._objs_seen: - if hasattr(obj, 'resume'): - obj.resume() - self._resume_task() - if self._interrupted: - raise RunEngineInterrupted(self.pause_msg) from None - return tuple(self._run_start_uids)
- - def _rewind(self): - '''Clean up in preparation for resuming from a pause or suspension. - - Returns - ------- - new_plan : generator - A new plan made from the messages in the message cache - - ''' - len_msg_cache = len(self._msg_cache) - new_plan = ensure_generator(list(self._msg_cache)) - self._msg_cache = deque() - if len_msg_cache: - for current_run in self._run_bundlers.values(): - current_run.rewind() - - return new_plan - - def _resume_task(self, *, init_func=None): - # Clear the blocking Event so that we can wait on it below. - # The task will set it when it is done, as it was previously - # configured to do it __call__. - self._blocking_event.clear() - - # Handle all context managers - with ExitStack() as stack: - for mgr in self.context_managers: - stack.enter_context(mgr(self)) - - if init_func is not None: - init_func() - - if self._task_fut is None or self._task_fut.done(): - return - - # The _run task is waiting on this Event. Let is continue. - self.loop.call_soon_threadsafe(self._run_permit.set) - try: - # Block until plan is complete or exception is raised. - try: - self._during_task.block(self._blocking_event) - except KeyboardInterrupt: - import ctypes - self._interrupted = True - # we can not interrupt a python thread from the outside - # but there is an API to schedule an exception to be raised - # the next time that thread would interpret byte code. - # The documentation of this function includes the sentence - # - # To prevent naive misuse, you must write your - # own C extension to call this. - # - # Here we cheat a bit and use ctypes. - num_threads = ctypes.pythonapi.PyThreadState_SetAsyncExc( - ctypes.c_ulong(self._th.ident), - ctypes.py_object(_RunEnginePanic)) - # however, if the thread is in a system call (such - # as sleep or I/O) there is no way to interrupt it - # (per decree of Guido) thus we give it a second - # to sort it's self out - task_finished = self._blocking_event.wait(1) - # before giving up and putting the RE in a - # non-recoverable panicked state. - if not task_finished or num_threads != 1: - self._state = 'panicked' - except Exception as raised_er: - self.halt() - self._interrupted = True - raise raised_er - finally: - if self._task_fut.done(): - # get exceptions from the main task - try: - exc = self._task_fut.exception() - except (asyncio.CancelledError, - concurrent.futures.CancelledError): - exc = None - # if the main task exception is not None, re-raise - # it (unless it is a canceled error) - if (exc is not None - and not isinstance(exc, _RunEnginePanic)): - raise exc - -
[docs] def install_suspender(self, suspender): - """ - Install a 'suspender', which can suspend and resume execution. - - Parameters - ---------- - suspender : `bluesky.suspenders.SuspenderBase` - - See Also - -------- - :meth:`RunEngine.remove_suspender` - :meth:`RunEngine.clear_suspenders` - """ - self._suspenders.add(suspender) - suspender.install(self)
- - async def _install_suspender(self, msg): - """ - See :meth: `RunEngine.install_suspender` - - Expected message object is: - - Msg('install_suspender', None, suspender) - """ - suspender = msg.args[0] - self.install_suspender(suspender) - -
[docs] def remove_suspender(self, suspender): - """ - Uninstall a suspender. - - Parameters - ---------- - suspender : `bluesky.suspenders.SuspenderBase` - - See Also - -------- - :meth:`RunEngine.install_suspender` - :meth:`RunEngine.clear_suspenders` - """ - if suspender in self._suspenders: - suspender.remove() - self._suspenders.discard(suspender)
- - async def _remove_suspender(self, msg): - """ - See :meth: `RunEngine.remove_suspender` - - Expected message object is: - - Msg('remove_suspender', None, suspender) - """ - suspender = msg.args[0] - self.remove_suspender(suspender) - -
[docs] def clear_suspenders(self): - """ - Uninstall all suspenders. - - See Also - -------- - :meth:`RunEngine.install_suspender` - :meth:`RunEngine.remove_suspender` - """ - for sus in self.suspenders: - self.remove_suspender(sus)
- -
[docs] def request_suspend(self, fut, *, pre_plan=None, post_plan=None, - justification=None): - """Request that the run suspend itself until the future is finished. - - The two plans will be run before and after waiting for the future. - This enable doing things like opening and closing shutters and - resetting cameras around a suspend. - - Parameters - ---------- - fut : asyncio.Future - - pre_plan : iterable or callable, optional - Plan to execute just before suspending. If callable, must - take no arguments. - - post_plan : iterable or callable, optional - Plan to execute just before resuming. If callable, must - take no arguments. - - justification : str, optional - explanation of why the suspension has been requested - - """ - - print("Suspending....To get prompt hit Ctrl-C twice to pause.") - ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - print("Suspension occurred at {}.".format(ts)) - - async def _request_suspend(pre_plan, post_plan, justification): - if not self.resumable: - print("No checkpoint; cannot suspend.") - print("Aborting: running cleanup and marking " - "exit_status as 'abort'...") - self._interrupted = True - with self._state_lock: - self._exception = FailedPause() - was_paused = self._state == 'paused' - self._state = 'aborting' - if not was_paused: - self._task.cancel() - - if justification is not None: - print("Justification for this suspension:\n%s" % justification) - for current_run in self._run_bundlers.values(): - current_run.record_interruption('resume') - # During suspend, all motors should be stopped. Call stop() on - # every object we ever set(). - self._stop_movable_objects(success=True) - # Notify Devices of the pause in case they want to clean up. - for obj in self._objs_seen: - if hasattr(obj, 'pause'): - try: - obj.pause() - except NoReplayAllowed: - self._reset_checkpoint_state_meth() - - # rewind to the last checkpoint - new_plan = self._rewind() - # queue up the cached messages - self._plan_stack.append(new_plan) - self._response_stack.append(None) - - self._plan_stack.append(single_gen( - Msg('rewindable', None, self.rewindable))) - self._response_stack.append(None) - - # if there is a post plan add it between the wait - # and the cached messages - if post_plan is not None: - if callable(post_plan): - post_plan = post_plan() - self._plan_stack.append(ensure_generator(post_plan)) - self._response_stack.append(None) - - # tell the devices they are ready to go again - self._plan_stack.append(single_gen(Msg('resume', None, ))) - self._response_stack.append(None) - - # add the wait on the future to the stack - self._plan_stack.append(single_gen(Msg('wait_for', None, [fut, ]))) - self._response_stack.append(None) - - # if there is a pre plan add on top of the wait - if pre_plan is not None: - if callable(pre_plan): - pre_plan = pre_plan() - self._plan_stack.append(ensure_generator(pre_plan)) - self._response_stack.append(None) - - self._plan_stack.append(single_gen( - Msg('rewindable', None, False))) - self._response_stack.append(None) - # The event loop is still running. The pre_plan will be processed, - # and then the RunEngine will be hung up on processing the - # 'wait_for' message until `fut` is set. - if not self._state == 'paused': - self._state = 'suspending' - # bump the _run task out of what ever it is awaiting - self._task.cancel() - - self.loop.call_soon_threadsafe( - self.loop.create_task, - _request_suspend(pre_plan, post_plan, justification))
- -
[docs] def abort(self, reason=''): - """ - Stop a running or paused plan and mark it as aborted. - - See Also - -------- - :meth:`RunEngine.halt` - :meth:`RunEngine.stop` - """ - return self.__interrupter_helper(self._abort_coro(reason))
- - async def _abort_coro(self, reason): - if self._state.is_idle: - raise TransitionError("RunEngine is already idle.") - print("Aborting: running cleanup and marking " - "exit_status as 'abort'...") - self._interrupted = True - self._reason = reason - - self._exit_status = 'abort' - - was_paused = self._state == 'paused' - self._state = 'aborting' - if was_paused: - with self._state_lock: - self._exception = RequestAbort() - else: - self._task.cancel() - for task in self._status_tasks: - task.cancel() - - return tuple(self._run_start_uids) - -
[docs] def stop(self): - """ - Stop a running or paused plan, but mark it as successful (not aborted). - - See Also - -------- - :meth:`RunEngine.abort` - :meth:`RunEngine.halt` - """ - return self.__interrupter_helper(self._stop_coro())
- - async def _stop_coro(self): - if self._state.is_idle: - raise TransitionError("RunEngine is already idle.") - print("Stopping: running cleanup and marking exit_status " - "as 'success'...") - - self._interrupted = True - was_paused = self._state == 'paused' - self._state = 'stopping' - if was_paused: - with self._state_lock: - self._exception = RequestStop - else: - self._task.cancel() - - return tuple(self._run_start_uids) - -
[docs] def halt(self): - ''' - Stop the running plan and do not allow the plan a chance to clean up. - - See Also - -------- - :meth:`RunEngine.abort` - :meth:`RunEngine.stop` - ''' - return self.__interrupter_helper(self._halt_coro())
- - def __interrupter_helper(self, coro): - if self.state == 'panicked': - raise RuntimeError("The RunEngine is panicked and " - "cannot be recovered. " - "You must restart bluesky.") - - coro_event = threading.Event() - task = None - - def end_cb(fut): - coro_event.set() - - def start_task(): - nonlocal task - task = self.loop.create_task(coro) - task.add_done_callback(end_cb) - - was_paused = self._state == 'paused' - self.loop.call_soon_threadsafe(start_task) - coro_event.wait() - if was_paused: - self._resume_task() - - return task.result() - - async def _halt_coro(self): - if self._state.is_idle: - raise TransitionError("RunEngine is already idle.") - print("Halting: skipping cleanup and marking exit_status as " - "'abort'...") - self._interrupted = True - was_paused = self._state == 'paused' - self._state = 'halting' - if was_paused: - with self._state_lock: - self._exception = PlanHalt - self._exit_status = 'abort' - else: - self._task.cancel() - - return tuple(self._run_start_uids) - - def _stop_movable_objects(self, *, success=True): - "Call obj.stop() for all objects we have moved. Log any exceptions." - for obj in self._movable_objs_touched: - try: - stop = obj.stop - except AttributeError: - self.log.debug("No 'stop' method available on %r", obj) - else: - try: - stop(success=success) - except Exception: - self.log.exception("Failed to stop %r.", obj) - - async def _run(self): - """Pull messages from the plan, process them, send results back. - - Upon exit, clean up. - - Call stop() on all objects that were 'set' or 'kickoff'. - - Try to collect any uncollected flyers. - - Try to unstage any devices left staged by the plan. - - Try to remove any monitoring subscriptions left on by the plan. - - If interrupting the middle of a run, try to emit a RunStop document. - """ - await self._run_permit.wait() - # grab the current task. We need to do this here because the - # object returned by `run_coroutine_threadsafe` is a future - # that acts as a proxy that does not have the correct behavior - # when `.cancel` is called on it. - with self._state_lock: - self._task = current_task(self.loop) - stashed_exception = None - debug = msg_logger.debug - self._reason = '' - # sentinel to decide if need to add to the response stack or not - sentinel = object() - exit_reason = '' - try: - self._state = 'running' - while True: - if self._state in ('pausing', 'suspending'): - if not self.resumable: - self._run_permit.set() - stashed_exception = FailedPause() - for task in self._status_tasks: - task.cancel() - self._state = 'aborting' - continue - # currently only using 'suspending' to get us into the - # block above, we do not have a 'suspended' state - # (yet) - if self._state == 'suspending': - self._state = 'running' - if not self._run_permit.is_set(): - # A pause has been requested. First, put everything in a - # resting state. - assert self._state == 'pausing' - # Remove any monitoring callbacks, but keep refs in - # self._monitor_params to re-instate them later. - for current_run in self._run_bundlers.values(): - await current_run.suspend_monitors() - # During pause, all motors should be stopped. Call stop() - # on every object we ever set(). - self._stop_movable_objects(success=True) - # Notify Devices of the pause in case they want to - # clean up. - for obj in self._objs_seen: - if hasattr(obj, 'pause'): - try: - obj.pause() - except NoReplayAllowed: - self._reset_checkpoint_state_meth() - self._state = 'paused' - # Let RunEngine.__call__ return... - self._blocking_event.set() - - await self._run_permit.wait() - # Restore any monitors - for current_run in self._run_bundlers.values(): - await current_run.restore_monitors() - if self._state == 'paused': - # may be called by 'resume', 'stop', 'abort', 'halt' - self._state = 'running' - - # If we are here, we have come back to life either to - # continue (resume) or to clean up before exiting. - - assert len(self._response_stack) == len(self._plan_stack) - # set resp to the sentinel so that if we fail in the sleep - # we do not add an extra response - resp = sentinel - try: - # the new response to be added - new_response = None - - # This 'await' must be here to ensure that - # this coroutine breaks out of its current behavior - # before trying to get the next message from the - # top of the generator stack in case there has - # been a pause requested. Without this the next - # message after the pause may be processed first - # on resume (instead of the first message in - # self._msg_cache). - - # This sleep has to be inside of this try block so - # that any of the 'async' exceptions get thrown in the - # correct place - await asyncio.sleep(0, loop=self._loop_for_kwargs) - # always pop off a result, we are either sending it back in - # or throwing an exception in, in either case the left hand - # side of the yield in the plan will be moved past - resp = self._response_stack.pop() - # if any status tasks have failed, grab the exceptions. - # give priority to things pushed in from outside - with self._state_lock: - if self._exception is not None: - stashed_exception = self._exception - self._exception = None - # The case where we have a stashed exception - if (stashed_exception is not None or - isinstance(resp, Exception)): - # throw the exception at the current plan - try: - msg = self._plan_stack[-1].throw( - stashed_exception or resp) - except Exception as e: - # The current plan did not handle it, - # maybe the next plan (if any) would like - # to try - self._plan_stack.pop() - # we have killed the current plan, do not give - # it a new response - resp = sentinel - if len(self._plan_stack): - stashed_exception = e - continue - # no plans left and still an unhandled exception - # re-raise to exit the infinite loop - else: - raise - # clear the stashed exception, the top plan - # handled it. - else: - stashed_exception = None - # The normal case of clean operation - else: - try: - msg = self._plan_stack[-1].send(resp) - # We have exhausted the top generator - except StopIteration: - # pop the dead generator go back to the top - self._plan_stack.pop() - # we have killed the current plan, do not give - # it a new response - resp = sentinel - if len(self._plan_stack): - continue - # or reraise to get out of the infinite loop - else: - raise - # Any other exception that comes out of the plan - except Exception as e: - # pop the dead plan, stash the exception and - # go to the top of the loop - self._plan_stack.pop() - # we have killed the current plan, do not give - # it a new response - resp = sentinel - if len(self._plan_stack): - stashed_exception = e - continue - # or reraise to get out of the infinite loop - else: - raise - - # if we have a message hook, call it - if self.msg_hook is not None: - self.msg_hook(msg) - debug("%s(%r, *%r **%r, run=%r)", - msg.command, msg.obj, msg.args, msg.kwargs, - msg.run, extra={'msg_command': msg.command}) - - # update the running set of all objects we have seen - self._objs_seen.add(msg.obj) - - # if this message can be cached for rewinding, cache it - if (self._msg_cache is not None and - self._rewindable_flag and - msg.command not in self._UNCACHEABLE_COMMANDS): - # We have a checkpoint. - self._msg_cache.append(msg) - - # try to look up the coroutine to execute the command - try: - coro = self._command_registry[msg.command] - # replace KeyError with a local sub-class and go - # to top of the loop - except KeyError: - # TODO make this smarter - new_response = InvalidCommand(msg.command) - continue - - # try to finally run the command the user asked for - try: - # this is one of two places that 'async' - # exceptions (coming in via throw) can be - # raised - new_response = await coro(msg) - - # special case `CancelledError` and let the outer - # exception block deal with it. - except asyncio.CancelledError: - raise - # any other exception, stash it and go to the top of loop - except Exception as e: - new_response = e - continue - # normal use, if it runs cleanly, stash the response and - # go to the top of the loop - else: - continue - - except KeyboardInterrupt: - # This only happens if some external code captures SIGINT - # -- overriding the RunEngine -- and then raises instead - # of (properly) calling the RunEngine's handler. - # See https://github.com/NSLS-II/bluesky/pull/242 - print("An unknown external library has improperly raised " - "KeyboardInterrupt. Intercepting and triggering " - "a HALT.") - await self._halt_coro() - except asyncio.CancelledError as e: - if self._state == 'pausing': - # if we got a CancelledError and we are in the - # 'pausing' state clear the run permit and - # bounce to the top - self._run_permit.clear() - continue - if self._state in ('halting', 'stopping', 'aborting'): - # if we got this while just keep going in tear-down - exception_map = {'halting': PlanHalt, - 'stopping': RequestStop, - 'aborting': RequestAbort} - # if the exception is not set bounce to the top - if stashed_exception is None: - stashed_exception = exception_map[self.state] - continue - if self._state == 'suspending': - # just bounce to the top - continue - # if we are handling this twice, raise and leave the plans - # alone - if stashed_exception is e: - raise e - # the case where FailedPause, RequestAbort or a coro - # raised error is not already stashed in _exception - if stashed_exception is None: - stashed_exception = e - finally: - # if we poped a response and did not pop a plan, we need - # to put the new response back on the stack - if resp is not sentinel: - self._response_stack.append(new_response) - - except (StopIteration, RequestStop): - self._exit_status = 'success' - # TODO Is the sleep here necessary? - await asyncio.sleep(0, loop=self._loop_for_kwargs) - except (FailedPause, RequestAbort, asyncio.CancelledError, - PlanHalt): - self._exit_status = 'abort' - # TODO Is the sleep here necessary? - await asyncio.sleep(0, loop=self._loop_for_kwargs) - self.log.exception("Run aborted") - except GeneratorExit as err: - self._exit_status = 'fail' # Exception raises during 'running' - exit_reason = str(err) - raise ValueError from err - except Exception as err: - self._exit_status = 'fail' # Exception raises during 'running' - exit_reason = str(err) - self.log.exception("Run aborted") - raise err - finally: - if not exit_reason: - exit_reason = self._reason - # Some done_callbacks may still be alive in other threads. - # Block them from creating new 'failed status' tasks on the loop. - self._pardon_failures.set() - # call stop() on every movable object we ever set() - self._stop_movable_objects(success=True) - for current_run in self._run_bundlers.values(): - # Clear any uncleared monitoring callbacks. - current_run.clear_monitors() - # Try to collect any flyers that were kicked off but - # not finished. Some might not support partial - # collection. We swallow errors. - await current_run.backstop_collect() - # in case we were interrupted between 'stage' and 'unstage' - for obj in list(self._staged): - try: - obj.unstage() - except Exception: - self.log.exception("Failed to unstage %r.", obj) - self._staged.remove(obj) - - sys.stdout.flush() - # Emit RunStop if necessary. - for key, current_run in self._run_bundlers.items(): - if current_run.run_is_open: - try: - await current_run.close_run( - Msg('close_run', - exit_status=self._exit_status, - reason=exit_reason, - run_id=key)) - except Exception: - self.log.error( - "Failed to close run %r.", current_run) - self._run_bundlers.clear() - - for p in self._plan_stack: - try: - p.close() - except RuntimeError: - print('The plan {!r} tried to yield a value on close. ' - 'Please fix your plan.'.format(p)) - - self._state = 'idle' - - self.log.info("Cleaned up from plan %r", self._plan) - if isinstance(stashed_exception, asyncio.CancelledError): - raise stashed_exception - - async def _wait_for(self, msg): - """Instruct the RunEngine to wait for futures - - Expected message object is: - - Msg('wait_for', None, awaitable_factories, **kwargs) - - The keyword arguments will be passed through to `asyncio.wait`. - - The callables in awaitable_factories must have the signature :: - - def fut_fac() -> awaitable: - 'This must work multiple times' - - """ - futs, = msg.args - futs = [asyncio.ensure_future(f()) for f in futs] - await asyncio.wait(futs, loop=self._loop_for_kwargs, **msg.kwargs) - - async def _open_run(self, msg): - """Instruct the RunEngine to start a new "run" - - Expected message object is: - - Msg('open_run', None, **kwargs) - - where **kwargs are any additional metadata that should go into - the RunStart document - """ - # TODO extract this from the Msg - run_key = msg.run - if run_key in self._run_bundlers: - raise IllegalMessageSequence("A 'close_run' message was not " - "received before the 'open_run' " - "message") - - # Run scan_id calculation method - self.md['scan_id'] = self.scan_id_source(self.md) - - # For metadata below, info about plan passed to self.__call__ for. - plan_type = type(self._plan).__name__ - plan_name = getattr(self._plan, '__name__', '') - - # Combine metadata, in order of decreasing precedence: - md = ChainMap(self._metadata_per_call, # from kwargs to self.__call__ - msg.kwargs, # from 'open_run' Msg - {'plan_type': plan_type, # computed from self._plan - 'plan_name': plan_name}, - self.md) # stateful, persistent metadata - # The metadata is final. Validate it now, at the last moment. - # Use copy for some reasonable (admittedly not total) protection - # against users mutating the md with their validator. - self.md_validator(dict(md)) - - current_run = self._run_bundlers[run_key] = RunBundler( - md, self.record_interruptions, self.emit, self.emit_sync, self.log, - loop=self._loop_for_kwargs) - - new_uid = await current_run.open_run(msg) - self._run_start_uids.append(new_uid) - return new_uid - - async def _close_run(self, msg): - """Instruct the RunEngine to write the RunStop document - - Expected message object is: - - Msg('close_run', None, exit_status=None, reason=None) - - if *exit_stats* and *reason* are not provided, use the values - stashed on the RE. - """ - # TODO extract this from the Msg - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence("A 'close_run' message was not " - "received before the 'open_run' " - "message") from ke - ret = (await current_run.close_run(msg)) - del self._run_bundlers[run_key] - return ret - - async def _create(self, msg): - """Trigger the run engine to start bundling future obj.read() calls for - an Event document - - Expected message object is: - - Msg('create', None, name='primary') - Msg('create', name='primary') - - Note that the `name` kwarg will be the 'name' field of the resulting - descriptor. So descriptor['name'] = msg.kwargs['name']. - - Also note that changing the 'name' of the Event will create a new - Descriptor document. - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence("Cannot bundle readings without " - "an open run. That is, 'create' must " - "be preceded by 'open_run'.") from ke - return (await current_run.create(msg)) - - async def _read(self, msg): - """ - Add a reading to the open event bundle. - - Expected message object is: - - Msg('read', obj) - """ - obj = msg.obj - # actually _read_ the object - ret = obj.read(*msg.args, **msg.kwargs) - - if ret is None: - raise RuntimeError( - f"The read of {obj.name} returned None. " - "This is a bug in your object implementation, " - "`read` must return a dictionary.") - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError: - ... - else: - await current_run.read(msg, ret) - - return ret - - async def _monitor(self, msg): - """ - Monitor a signal. Emit event documents asynchronously. - - A descriptor document is emitted immediately. Then, a closure is - defined that emits Event documents associated with that descriptor - from a separate thread. This process is not related to the main - bundling process (create/read/save). - - Expected message object is: - - Msg('monitor', obj, **kwargs) - Msg('monitor', obj, name='event-stream-name', **kwargs) - - where kwargs are passed through to ``obj.subscribe()`` - """ - - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence("A 'monitor' message was sent but no " - "run is open.") from ke - await current_run.monitor(msg) - await self._reset_checkpoint_state_coro() - - async def _unmonitor(self, msg): - """ - Stop monitoring; i.e., remove the callback emitting event documents. - - Expected message object is: - - Msg('unmonitor', obj) - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence( - "A 'unmonitor' message was sent but no " - "run is open.") from ke - await current_run.unmonitor(msg) - await self._reset_checkpoint_state_coro() - - async def _save(self, msg): - """Save the event that is currently being bundled - - Expected message object is: - - Msg('save') - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - # sanity check -- this should be caught by 'create' which makes - # this code path impossible - raise IllegalMessageSequence( - "A 'save' message was sent but no " "run is open." - ) from ke - - await current_run.save(msg) - - async def _drop(self, msg): - """Drop the event that is currently being bundled - - Expected message object is: - - Msg('drop') - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence( - "A 'drop' message was sent but no " "run is open." - ) from ke - await current_run.drop(msg) - - async def _kickoff(self, msg): - """Start a flyscan object - - Special kwargs for the 'Msg' object in this function: - group : str - The blocking group to this flyer to - - Expected message object is: - - If `flyer_object` has a `kickoff` function that takes no arguments: - - Msg('kickoff', flyer_object) - Msg('kickoff', flyer_object, group=<name>) - - If `flyer_object` has a `kickoff` function that takes - `(start, stop, steps)` as its function arguments: - - Msg('kickoff', flyer_object, start, stop, step) - Msg('kickoff', flyer_object, start, stop, step, group=<name>) - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence("A 'kickoff' message was sent but no " - "run is open.") from ke - - _, obj, args, kwargs, _ = msg - kwargs = dict(msg.kwargs) - group = kwargs.pop("group", None) - - ret = obj.kickoff(*msg.args, **kwargs) - p_event = asyncio.Event(loop=self._loop_for_kwargs) - pardon_failures = self._pardon_failures - - await current_run.kickoff(msg) - - def done_callback(status=None): - self.log.debug( - "The object %r reports 'kickoff' is done " "with status %r", - msg.obj, - ret.success, - ) - task = self._loop.call_soon_threadsafe( - self._status_object_completed, ret, p_event, pardon_failures - ) - self._status_tasks.append(task) - - try: - ret.add_callback(done_callback) - except AttributeError: - # for ophyd < v0.8.0 - ret.finished_cb = done_callback - self._groups[group].add(p_event.wait) - self._status_objs[group].add(ret) - - return ret - - async def _complete(self, msg): - """ - Tell a flyer, 'stop collecting, whenever you are ready'. - - The flyer returns a status object. Some flyers respond to this - command by stopping collection and returning a finished status - object immediately. Other flyers finish their given course and - finish whenever they finish, irrespective of when this command is - issued. - - Expected message object is: - - Msg('complete', flyer, group=<GROUP>) - - where <GROUP> is a hashable identifier. - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence("A 'complete' message was sent but no " - "run is open.") from ke - - await current_run.complete(msg) - kwargs = dict(msg.kwargs) - group = kwargs.pop("group", None) - ret = msg.obj.complete(*msg.args, **kwargs) - - p_event = asyncio.Event(loop=self._loop_for_kwargs) - pardon_failures = self._pardon_failures - - def done_callback(status=None): - self.log.debug( - "The object %r reports 'complete' is done " "with status %r", - msg.obj, - ret.success, - ) - task = self._loop.call_soon_threadsafe( - self._status_object_completed, ret, p_event, pardon_failures - ) - self._status_tasks.append(task) - - try: - ret.add_callback(done_callback) - except AttributeError: - # for ophyd < v0.8.0 - ret.finished_cb = done_callback - self._groups[group].add(p_event.wait) - self._status_objs[group].add(ret) - return ret - - async def _collect(self, msg): - """ - Collect data cached by a flyer and emit documents - - Expected message object is: - - Msg('collect', flyer_object) - Msg('collect', flyer_object, stream=True, return_payload=False) - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError as ke: - raise IllegalMessageSequence("A 'collect' message was sent but no " - "run is open.") from ke - - return (await current_run.collect(msg)) - - async def _null(self, msg): - """ - A no-op message, mainly for debugging and testing. - """ - pass - - async def _RE_class(self, msg): - """ - A no-op message, mainly for debugging and testing. - """ - return type(self) - - async def _set(self, msg): - """ - Set a device and cache the returned status object. - - Also, note that the device has been touched so it can be stopped upon - exit. - - Expected message object is - - Msg('set', obj, *args, **kwargs) - - where arguments are passed through to `obj.set(*args, **kwargs)`. - """ - kwargs = dict(msg.kwargs) - group = kwargs.pop('group', None) - self._movable_objs_touched.add(msg.obj) - ret = msg.obj.set(*msg.args, **kwargs) - p_event = asyncio.Event(loop=self._loop_for_kwargs) - pardon_failures = self._pardon_failures - - def done_callback(status=None): - self.log.debug("The object %r reports set is done " - "with status %r", msg.obj, ret.success) - task = self._loop.call_soon_threadsafe( - self._status_object_completed, ret, p_event, pardon_failures) - self._status_tasks.append(task) - - try: - ret.add_callback(done_callback) - except AttributeError: - # for ophyd < v0.8.0 - ret.finished_cb = done_callback - self._groups[group].add(p_event.wait) - self._status_objs[group].add(ret) - - return ret - - async def _trigger(self, msg): - """ - Trigger a device and cache the returned status object. - - Expected message object is: - - Msg('trigger', obj) - """ - kwargs = dict(msg.kwargs) - group = kwargs.pop('group', None) - ret = msg.obj.trigger(*msg.args, **kwargs) - p_event = asyncio.Event(loop=self._loop_for_kwargs) - pardon_failures = self._pardon_failures - - def done_callback(status=None): - self.log.debug("The object %r reports trigger is " - "done with status %r.", msg.obj, ret.success) - task = self._loop.call_soon_threadsafe( - self._status_object_completed, ret, p_event, pardon_failures) - self._status_tasks.append(task) - - try: - ret.add_callback(done_callback) - except AttributeError: - # for ophyd < v0.8.0 - ret.finished_cb = done_callback - self._groups[group].add(p_event.wait) - self._status_objs[group].add(ret) - - return ret - - async def _wait(self, msg): - """Block progress until every object that was triggered or set - with the keyword argument `group=<GROUP>` is done. - - Expected message object is: - - Msg('wait', group=<GROUP>) - - where ``<GROUP>`` is any hashable key. - """ - if msg.args: - group, = msg.args - else: - group = msg.kwargs['group'] - futs = list(self._groups.pop(group, [])) - if futs: - status_objs = self._status_objs.pop(group) - try: - if self.waiting_hook is not None: - # Notify the waiting_hook function that the RunEngine is - # waiting for these status_objs to complete. Users can use - # the information these encapsulate to create a progress - # bar. - self.waiting_hook(status_objs) - await self._wait_for(Msg('wait_for', None, futs)) - finally: - if self.waiting_hook is not None: - # Notify the waiting_hook function that we have moved on by - # sending it `None`. If all goes well, it could have - # inferred this from the status_obj, but there are edge - # cases. - self.waiting_hook(None) - - def _status_object_completed(self, ret, p_event, pardon_failures): - """ - Created as a task on the loop when a status object is finished - - Parameters - ---------- - ret : status object - p_event : asyncio.Event - held in the RunEngine's self._groups cache for waiting - pardon_failuers : asyncio.Event - tells us whether the __call__ this status object is over - """ - if not ret.success and not pardon_failures.is_set(): - # TODO: need a better channel to move this information back - # to the run task. - with self._state_lock: - self._exception = FailedStatus(ret) - p_event.set() - - async def _sleep(self, msg): - """Sleep the event loop - - Expected message object is: - - Msg('sleep', None, sleep_time) - - where `sleep_time` is in seconds - """ - await asyncio.sleep(*msg.args, loop=self._loop_for_kwargs) - - async def _pause(self, msg): - """Request the run engine to pause - - Expected message object is: - - Msg('pause', defer=False, name=None, callback=None) - - See RunEngine.request_pause() docstring for explanation of the three - keyword arguments in the `Msg` signature - """ - await self._request_pause_coro(*msg.args, **msg.kwargs) - - async def _resume(self, msg): - """Request the run engine to resume - - Expected message object is: - - Msg('resume', defer=False, name=None, callback=None) - - See RunEngine.resume() docstring for explanation of the three - keyword arguments in the `Msg` signature - """ - # Re-instate monitoring callbacks. - for current_run in self._run_bundlers.values(): - await current_run.restore_monitors() - # Notify Devices of the resume in case they want to clean up. - for obj in self._objs_seen: - if hasattr(obj, 'resume'): - obj.resume() - - async def _checkpoint(self, msg): - """Instruct the RunEngine to create a checkpoint so that we can rewind - to this point if necessary - - Expected message object is: - - Msg('checkpoint') - """ - for current_run in self._run_bundlers.values(): - if current_run.bundling: - raise IllegalMessageSequence("Cannot 'checkpoint' after 'create' " - "and before 'save'. Aborting!") - - await self._reset_checkpoint_state_coro() - - if self._deferred_pause_requested: - # We are at a checkpoint; we are done deferring the pause. - # Give the _check_for_signals coroutine time to look for - # additional SIGINTs that would trigger an abort. - await asyncio.sleep(0.5, loop=self._loop_for_kwargs) - await self._request_pause_coro(defer=False) - - def _reset_checkpoint_state(self): - self._reset_checkpoint_state_meth() - - def _reset_checkpoint_state_meth(self): - if self._msg_cache is None: - return - - self._msg_cache = deque() - for current_run in self._run_bundlers.values(): - current_run.reset_checkpoint_state() - - async def _reset_checkpoint_state_coro(self): - self._reset_checkpoint_state() - - async def _clear_checkpoint(self, msg): - """Clear a set checkpoint - - Expected message object is: - - Msg('clear_checkpoint') - """ - # clear message cache - self._msg_cache = None - # clear stashed - for current_run in self._run_bundlers.values(): - await current_run.clear_checkpoint(msg) - - async def _rewindable(self, msg): - '''Set rewindable state of RunEngine - - Expected message object is: - - Msg('rewindable', None, bool or None) - ''' - - rw_flag, = msg.args - if rw_flag is not None: - self.rewindable = rw_flag - - return self.rewindable - - async def _configure(self, msg): - """Configure an object - - Expected message object is: - - Msg('configure', object, *args, **kwargs) - - which results in this call: - - object.configure(*args, **kwargs) - """ - run_key = msg.run - try: - current_run = self._run_bundlers[run_key] - except KeyError: - current_run = None - else: - if current_run.bundling: - raise IllegalMessageSequence( - "Cannot configure after 'create' but before 'save'" - "Aborting!") - _, obj, args, kwargs, _ = msg - - old, new = obj.configure(*args, **kwargs) - if current_run: - await current_run.configure(msg) - return old, new - - async def _stage(self, msg): - """Instruct the RunEngine to stage the object - - Expected message object is: - - Msg('stage', object) - """ - _, obj, args, kwargs, _ = msg - # If an object has no 'stage' method, assume there is nothing to do. - if not hasattr(obj, 'stage'): - return [] - result = obj.stage() - self._staged.add(obj) # add first in case of failure below - await self._reset_checkpoint_state_coro() - return result - - async def _unstage(self, msg): - """Instruct the RunEngine to unstage the object - - Expected message object is: - - Msg('unstage', object) - """ - _, obj, args, kwargs, _ = msg - # If an object has no 'unstage' method, assume there is nothing to do. - if not hasattr(obj, 'unstage'): - return [] - result = obj.unstage() - # use `discard()` to ignore objects that are not in the staged set. - self._staged.discard(obj) - await self._reset_checkpoint_state_coro() - return result - - async def _stop(self, msg): - """ - Stop a device. - - Expected message object is: - - Msg('stop', obj) - """ - return msg.obj.stop() # nominally, this returns None - - async def _subscribe(self, msg): - """ - Add a subscription after the run has started. - - This, like subscriptions passed to __call__, will be removed at the - end by the RunEngine. - - Expected message object is: - - Msg('subscribe', None, callback_function, document_name) - - where `document_name` is one of: - - {'start', 'descriptor', 'event', 'stop', 'all'} - - and `callback_function` is expected to have a signature of: - - ``f(name, document)`` - - where name is one of the ``document_name`` options and ``document`` - is one of the document dictionaries in the event model. - - See the docstring of bluesky.run_engine.Dispatcher.subscribe() for more - information. - """ - self.log.debug("Adding subscription %r", msg) - _, obj, args, kwargs, _ = msg - token = self.subscribe(*args, **kwargs) - self._temp_callback_ids.add(token) - await self._reset_checkpoint_state_coro() - return token - - async def _unsubscribe(self, msg): - """ - Remove a subscription during a call -- useful for a multi-run call - where subscriptions are wanted for some runs but not others. - - Expected message object is: - - Msg('unsubscribe', None, TOKEN) - Msg('unsubscribe', token=TOKEN) - - where ``TOKEN`` is the return value from ``RunEngine._subscribe()`` - """ - self.log.debug("Removing subscription %r", msg) - _, obj, args, kwargs, _ = msg - try: - token = kwargs['token'] - except KeyError: - token, = args - self.unsubscribe(token) - self._temp_callback_ids.remove(token) - await self._reset_checkpoint_state_coro() - - async def _input(self, msg): - """ - Process a 'input' Msg. Expected Msg: - - Msg('input', None) - Msg('input', None, prompt='>') # customize prompt - """ - prompt = msg.kwargs.get('prompt', '') - async_input = AsyncInput(self.loop) - async_input = functools.partial(async_input, end='', flush=True) - return (await async_input(prompt)) - - def emit_sync(self, name, doc): - "Process blocking callbacks and schedule non-blocking callbacks." - schema_validators[name].validate(doc) - self.dispatcher.process(name, doc) - - async def emit(self, name, doc): - self.emit_sync(name, doc)
- - -
[docs]class Dispatcher: - """Dispatch documents to user-defined consumers on the main thread.""" - -
[docs] def __init__(self): - self.cb_registry = CallbackRegistry(allowed_sigs=DocumentNames) - self._counter = count() - self._token_mapping = dict()
- -
[docs] def process(self, name, doc): - """ - Dispatch document ``doc`` of type ``name`` to the callback registry. - - Parameters - ---------- - name : {'start', 'descriptor', 'event', 'stop'} - doc : dict - """ - exceptions = self.cb_registry.process(name, name.name, doc) - for exc, traceback in exceptions: - warn("A %r was raised during the processing of a %s " - "Document. The error will be ignored to avoid " - "interrupting data collection. To investigate, " - "set RunEngine.ignore_callback_exceptions = False " - "and run again." % (exc, name.name))
- -
[docs] def subscribe(self, func, name='all'): - """ - Register a callback function to consume documents. - - .. versionchanged :: 0.10.0 - The order of the arguments was swapped and the ``name`` - argument has been given a default value, ``'all'``. Because the - meaning of the arguments is unambiguous (they must be a callable - and a string, respectively) the old order will be supported - indefinitely, with a warning. - - .. versionchanged :: 0.10.0 - The order of the arguments was swapped and the ``name`` - argument has been given a default value, ``'all'``. Because the - meaning of the arguments is unambiguous (they must be a callable - and a string, respectively) the old order will be supported - indefinitely, with a warning. - - Parameters - ---------- - func: callable - expecting signature like ``f(name, document)`` - where name is a string and document is a dict - name : {'all', 'start', 'descriptor', 'event', 'stop'}, optional - the type of document this function should receive ('all' by - default). - - Returns - ------- - token : int - an integer ID that can be used to unsubscribe - - See Also - -------- - :meth:`Dispatcher.unsubscribe` - an integer token that can be used to unsubscribe - """ - if callable(name) and isinstance(func, str): - name, func = func, name - warn("The order of the arguments has been changed. Because the " - "meaning of the arguments is unambiguous, the old usage will " - "continue to work indefinitely, but the new usage is " - "encouraged: call subscribe(func, name) instead of " - "subscribe(name, func). Additionally, the 'name' argument " - "has become optional. Its default value is 'all'.") - if name == 'all': - private_tokens = [] - for key in DocumentNames: - private_tokens.append(self.cb_registry.connect(key, func)) - public_token = next(self._counter) - self._token_mapping[public_token] = private_tokens - return public_token - - name = DocumentNames[name] - private_token = self.cb_registry.connect(name, func) - public_token = next(self._counter) - self._token_mapping[public_token] = [private_token] - return public_token
- -
[docs] def unsubscribe(self, token): - """ - Unregister a callback function using its integer ID. - - Parameters - ---------- - token : int - the integer ID issued by :meth:`Dispatcher.subscribe` - - See Also - -------- - :meth:`Dispatcher.subscribe` - """ - for private_token in self._token_mapping[token]: - self.cb_registry.disconnect(private_token)
- -
[docs] def unsubscribe_all(self): - """Unregister all callbacks from the dispatcher - """ - for public_token in self._token_mapping.keys(): - self.unsubscribe(public_token)
- - @property - def ignore_exceptions(self): - return self.cb_registry.ignore_exceptions - - @ignore_exceptions.setter - def ignore_exceptions(self, val): - self.cb_registry.ignore_exceptions = val
- - -PAUSE_MSG = """ -Your RunEngine is entering a paused state. These are your options for changing -the state of the RunEngine: - -RE.resume() Resume the plan. -RE.abort() Perform cleanup, then kill plan. Mark exit_stats='aborted'. -RE.stop() Perform cleanup, then kill plan. Mark exit_status='success'. -RE.halt() Emergency Stop: Do not perform cleanup --- just stop. -""" - - -MAX_DEPTH_EXCEEDED_ERR_MSG = """ -RunEngine.max_depth is set to {}; depth of {} was detected. - -The RunEngine should not be called from inside another function. Doing so -breaks introspection tools and can result in unexpected behavior in the event -of an interruption. See documentation for more information and what to do -instead: - -http://nsls-ii.github.io/bluesky/plans_intro.html#combining-plans -""" - - -def _default_md_validator(md): - if 'sample' in md and not (hasattr(md['sample'], 'keys') or - isinstance(md['sample'], str)): - raise ValueError( - "You specified 'sample' metadata. We give this field special " - "significance in order to make your data easily searchable. " - "Therefore, you must make 'sample' a string or a " - "dictionary, like so: " - "GOOD: sample='dirt' " - "GOOD: sample={'color': 'red', 'number': 5} " - "BAD: sample=[1, 2] ") - - -def _ensure_event_loop_running(loop): - """ - Run an asyncio event loop forever on a background thread. - - This is idempotent: if the loop is already running nothing will be done. - """ - if not loop.is_running(): - th = threading.Thread(target=loop.run_forever, daemon=True, name="bluesky-run-engine") - th.start() - _ensure_event_loop_running.loop_to_thread[loop] = th - else: - th = _ensure_event_loop_running.loop_to_thread[loop] - return th - - -_ensure_event_loop_running.loop_to_thread = weakref.WeakKeyDictionary() - -_bluesky_event_loop = None - - -def get_bluesky_event_loop(): - global _bluesky_event_loop - if _bluesky_event_loop is None: - _bluesky_event_loop = asyncio.new_event_loop() - return _bluesky_event_loop - - -def set_bluesky_event_loop(loop): - global _bluesky_event_loop - _bluesky_event_loop = loop -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/simulators.html b/bluesky/_modules/bluesky/simulators.html deleted file mode 100644 index 319edf92c2..0000000000 --- a/bluesky/_modules/bluesky/simulators.html +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - - - - - bluesky.simulators — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.simulators
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.simulators

-from warnings import warn
-from bluesky.preprocessors import print_summary_wrapper
-
-
-
[docs]def plot_raster_path(plan, x_motor, y_motor, ax=None, probe_size=None, lw=2): - """Plot the raster path for this plan - - Parameters - ---------- - plan : iterable - Must yield `Msg` objects and not be a co-routine - - x_motor, y_motor : str - Names of the x and y motors - - ax : matplotlib.axes.Axes - The axes to plot to, if none, make new figure + axes - - probe_size : float, optional - If not None, use as radius of probe (in same units as motor positions) - - lw : float, optional - Width of lines drawn between points - """ - import matplotlib.pyplot as plt - from matplotlib import collections as mcollections - from matplotlib import patches as mpatches - if ax is None: - ax = plt.subplots()[1] - ax.set_aspect('equal') - - cur_x = cur_y = None - traj = [] - for msg in plan: - cmd = msg.command - if cmd == 'set': - if msg.obj.name == x_motor: - cur_x = msg.args[0] - if msg.obj.name == y_motor: - cur_y = msg.args[0] - elif cmd == 'save': - traj.append((cur_x, cur_y)) - - x, y = zip(*traj) - path, = ax.plot(x, y, marker='', linestyle='-', lw=lw) - ax.set_xlabel(x_motor) - ax.set_ylabel(y_motor) - if probe_size is None: - read_points = ax.scatter(x, y, marker='o', lw=lw) - else: - circles = [mpatches.Circle((_x, _y), probe_size, - facecolor='black', alpha=0.5) - for _x, _y in traj] - - read_points = mcollections.PatchCollection(circles, - match_original=True) - ax.add_collection(read_points) - return {'path': path, 'events': read_points}
- - -
[docs]def summarize_plan(plan): - """Print summary of plan - - Prints a minimal version of the plan, showing only moves and - where events are created. - - Parameters - ---------- - plan : iterable - Must yield `Msg` objects - """ - for msg in print_summary_wrapper(plan): - ...
- - -print_summary = summarize_plan # back-compat - - -
[docs]def check_limits(plan): - """ - Check that a plan will not move devices outside of their limits. - - Parameters - ---------- - plan : iterable - Must yield `Msg` objects - """ - ignore = [] - for msg in plan: - if msg.command == 'set' and msg.obj not in ignore: - if hasattr(msg.obj, "check_value"): - msg.obj.check_value(msg.args[0]) - else: - warn(f"{msg.obj.name} has no check_value() method" - f" to check if {msg.args[0]} is within its limits.") - ignore.append(msg.obj)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/suspenders.html b/bluesky/_modules/bluesky/suspenders.html deleted file mode 100644 index 5a70d46b92..0000000000 --- a/bluesky/_modules/bluesky/suspenders.html +++ /dev/null @@ -1,938 +0,0 @@ - - - - - - - - - - bluesky.suspenders — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.suspenders
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.suspenders

-import asyncio
-from datetime import datetime, timedelta
-from abc import ABCMeta, abstractmethod, abstractproperty
-import operator
-import threading
-from functools import partial
-from warnings import warn
-
-
-class SuspenderBase(metaclass=ABCMeta):
-    """An ABC to manage the callbacks between asyincio and pyepics.
-
-
-    Parameters
-    ----------
-    signal : `ophyd.Signal`
-        The signal to watch for changes to determine if the
-        scan should be suspended
-
-    sleep : float, optional
-        How long to wait in seconds after the resume condition is met
-        before marking the event as done.  Defaults to 0
-
-    pre_plan : iterable or iterator or generator function, optional
-            a generator, list, or similar containing `Msg` objects
-
-    post_plan : iterable or iterator or generator function, optional
-            a generator, list, or similar containing `Msg` objects
-
-    tripped_message : str, optional
-        Message to include in the trip notification
-    """
-    def __init__(self, signal, *, sleep=0, pre_plan=None, post_plan=None,
-                 tripped_message=''):
-        """
-        """
-        self.RE = None
-        self._ev = None
-        self._tripped = False
-        self._tripped_message = tripped_message
-        self._sleep = sleep
-        self._lock = threading.Lock()
-        self._sig = signal
-        self._pre_plan = pre_plan
-        self._post_plan = post_plan
-
-    def __repr__(self):
-        return (
-            "{}({!r}, sleep={}, pre_plan={}, post_plan={},"
-            "tripped_message={})".format(
-                type(self).__name__,
-                self._sig,
-                self._sleep,
-                self._pre_plan,
-                self._post_plan,
-                self._tripped_message,
-            )
-        )
-
-    def install(self, RE, *, event_type=None):
-        """Install callback on signal
-
-        This (re)installs the required callbacks at the pyepics level
-
-        Parameters
-        ----------
-
-        RE : RunEngine
-            The run engine instance this should work on
-
-        event_type : str, optional
-            The event type (subscription type) to watch
-        """
-        with self._lock:
-            self.RE = RE
-        self._sig.subscribe(self, event_type=event_type, run=True)
-
-    def remove(self):
-        """Disable the suspender
-
-        Removes the callback at the pyepics level
-        """
-        self._sig.clear_sub(self)
-        with self._lock:
-            if self.RE is not None:
-                self.__set_event(self.RE._loop)
-            self.RE = None
-            self._tripped = False
-
-    @abstractmethod
-    def _should_suspend(self, value):
-        """
-        Determine if the current value of the signal is such
-        that we need to tell the scan to suspend
-
-        Parameters
-        ----------
-        value : object
-            The value to evaluate to determine if we should
-            suspend
-
-        Returns
-        -------
-        suspend : bool
-            True means suspend
-        """
-        raise NotImplementedError()
-
-    @abstractmethod
-    def _should_resume(self, value):
-        """
-        Determine if the scan is ready to automatically
-        restart.
-
-        Parameters
-        ----------
-        value : object
-            The value to evaluate to determine if we should
-            resume
-
-        Returns
-        -------
-        suspend : bool
-            True means resume
-        """
-        raise NotImplementedError()
-
-    def __call__(self, value, **kwargs):
-        """Make the class callable so that we can
-        pass it off to the ophyd callback stack.
-
-        This expects the massive blob that comes from ophyd
-        """
-        with self._lock:
-            if self.RE is None:
-                return
-            loop = self.RE._loop
-
-            if self._should_suspend(value):
-                self._tripped = True
-                # this does dirty things with internal state
-                if self._ev is None and self.RE is not None:
-                    self.__make_event()
-                    if self._ev is None:
-                        raise RuntimeError("Could not create the ")
-                    cb = partial(
-                        self.RE.request_suspend,
-                        self._ev.wait,
-                        pre_plan=self._pre_plan,
-                        post_plan=self._post_plan,
-                        justification=self._get_justification(),
-                    )
-                    if self.RE.state.is_running:
-                        loop.call_soon_threadsafe(cb)
-            elif self._should_resume(value):
-                self.__set_event(loop)
-                self._tripped = False
-
-    def __make_event(self):
-        """Make or return the asyncio.Event to use as a bridge."""
-        assert self._lock.locked()
-        if self._ev is None and self.RE is not None:
-            th_ev = threading.Event()
-
-            def really_make_the_event():
-                self._ev = asyncio.Event()
-                th_ev.set()
-
-            h = self.RE._loop.call_soon_threadsafe(really_make_the_event)
-            if not th_ev.wait(0.1):
-                h.cancel()
-        return self._ev
-
-    def __set_event(self, loop):
-        """Notify the event that it can resume"""
-        assert self._lock.locked()
-        if self._ev:
-            ev = self._ev
-            sleep = self._sleep
-
-            def local():
-                ts = (datetime.now() + timedelta(seconds=sleep)).strftime(
-                    "%Y-%m-%d %H:%M:%S"
-                )
-                print(
-                    "Suspender {!r} reports a return to nominal "
-                    "conditions. Will sleep for {} seconds and then "
-                    "release suspension at {}.".format(self, sleep, ts)
-                )
-                # we can use call_later here because this function
-                # is scheduled to be run in the event loop thread
-                # by the `call_soon_threadsafe` call just below.
-                loop.call_later(sleep, ev.set)
-
-            loop.call_soon_threadsafe(local)
-        # clear that we have an event
-        self._ev = None
-
-    def get_futures(self):
-        """Return a list of futures to wait on.
-
-        This will only work correctly if this suspender is 'installed'
-        and watching a signal
-
-        Returns
-        -------
-        futs : list
-            List of futures to wait on
-
-        justification : str
-            String explaining why the suspender is tripped
-        """
-        if not self.tripped:
-            return [], ""
-        with self._lock:
-            return [self.__make_event().wait], self._get_justification()
-
-    @property
-    def tripped(self):
-        return self._tripped
-
-    def _get_justification(self):
-        if not self.tripped:
-            return ''
-
-        template = 'Suspender of type {} stopped by signal {!r}'
-        just = template.format(self.__class__.__name__, self._sig)
-        return ': '.join(s for s in (just, self._tripped_message)
-                         if s)
-
-
-
[docs]class SuspendBoolHigh(SuspenderBase): - """ - Suspend when a boolean signal goes high; resume when it goes low. - - Parameters - ---------- - signal : `ophyd.Signal` - The signal to watch for changes to determine if the - scan should be suspended - - sleep : float, optional - How long to wait in seconds after the resume condition is met - before marking the event as done. Defaults to 0 - - pre_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - - post_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - """ - - def _should_suspend(self, value): - return bool(value) - - def _should_resume(self, value): - return not bool(value) - - def _get_justification(self): - if not self.tripped: - return '' - - just = 'Signal {} is high'.format(self._sig.name) - return ': '.join(s for s in (just, self._tripped_message) - if s)
- - -
[docs]class SuspendBoolLow(SuspenderBase): - """ - Suspend when a boolean signal goes low; resume when it goes high. - - Parameters - ---------- - signal : `ophyd.Signal` - The signal to watch for changes to determine if the - scan should be suspended - - sleep : float, optional - How long to wait in seconds after the resume condition is met - before marking the event as done. Defaults to 0 - - pre_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - - post_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - """ - - def _should_suspend(self, value): - return not bool(value) - - def _should_resume(self, value): - return bool(value) - - def _get_justification(self): - if not self.tripped: - return '' - - just = 'Signal {} is low'.format(self._sig.name) - return ': '.join(s for s in (just, self._tripped_message) - if s)
- - -class _Threshold(SuspenderBase): - """ - Private base class for suspenders that watch when a scalar - signal fall above or below a threshold. Allow for a possibly different - threshold to resume. - """ - def __init__(self, signal, suspend_thresh, *, - resume_thresh=None, **kwargs): - super().__init__(signal, **kwargs) - self._suspend_thresh = suspend_thresh - if resume_thresh is None: - resume_thresh = suspend_thresh - self._resume_thresh = resume_thresh - self._validate() - - def _should_suspend(self, value): - return self._op(value, self._suspend_thresh) - - def _should_resume(self, value): - return not self._op(value, self._resume_thresh) - - @abstractproperty - def _op(self): - pass - - @abstractmethod - def _validate(self): - pass - - -
[docs]class SuspendFloor(_Threshold): - """ - Suspend when a scalar falls below a threshold. - - Optionally, the threshold to resume can be set to be greater than the - threshold to suspend. - - Parameters - ---------- - signal : `ophyd.Signal` - The signal to watch for changes to determine if the - scan should be suspended - - suspend_thresh : float - Suspend if the signal value falls below this value - - resume_thresh : float, optional - Resume when the signal value rises above this value. If not - given set to `suspend_thresh`. Must be greater than `suspend_thresh`. - - sleep : float, optional - How long to wait in seconds after the resume condition is met - before marking the event as done. Defaults to 0 - - pre_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - - post_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - """ - def _validate(self): - if self._resume_thresh < self._suspend_thresh: - raise ValueError("Resume threshold must be equal or greater " - "than suspend threshold, you passed: " - "suspend: {} resume: {}".format( - self._suspend_thresh, - self._resume_thresh)) - - @property - def _op(self): - return operator.lt - - def _get_justification(self): - if not self.tripped: - return '' - - just = ('Signal {} = {!r} is below {}' - ''.format(self._sig.name, self._sig.get(), - self._suspend_thresh) - ) - return ': '.join(s for s in (just, self._tripped_message) - if s)
- - -
[docs]class SuspendCeil(_Threshold): - """ - Suspend when a scalar rises above a threshold. - - Optionally, the threshold to resume can be set to be less than the - threshold to suspend. - - Parameters - ---------- - signal : `ophyd.Signal` - The signal to watch for changes to determine if the - scan should be suspended - - suspend_thresh : float - Suspend if the signal value falls below this value - - resume_thresh : float, optional - Resume when the signal value rises above this value. If not - given set to `suspend_thresh`. Must be greater than `suspend_thresh`. - - sleep : float, optional - How long to wait in seconds after the resume condition is met - before marking the event as done. Defaults to 0 - - pre_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - - post_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - """ - def _validate(self): - if self._resume_thresh > self._suspend_thresh: - raise ValueError("Resume threshold must be equal or less " - "than suspend threshold, you passed: " - "suspend: {} resume: {}".format( - self._suspend_thresh, - self._resume_thresh)) - - @property - def _op(self): - return operator.gt - - def _get_justification(self): - if not self.tripped: - return '' - - just = ('Signal {} = {!r} is above {}' - ''.format(self._sig.name, self._sig.get(), - self._suspend_thresh) - ) - return ': '.join(s for s in (just, self._tripped_message) - if s)
- - -class _SuspendBandBase(SuspenderBase): - """ - Private base-class for suspenders based on keeping a scalar inside - or outside of a band - """ - def __init__(self, signal, band_bottom, band_top, **kwargs): - super().__init__(signal, **kwargs) - if not band_bottom < band_top: - raise ValueError("The bottom of the band must be strictly " - "less than the top of the band.\n" - "bottom: {}\ttop: {}".format( - band_bottom, band_top) - ) - self._bot = band_bottom - self._top = band_top - - -
[docs]class SuspendWhenOutsideBand(_SuspendBandBase): - """ - Suspend when a scalar signal leaves a given band of values. - - Parameters - ---------- - signal : `ophyd.Signal` - The signal to watch for changes to determine if the - scan should be suspended - - band_bottom, band_top : float - The top and bottom of the band. `band_top` must be - strictly greater than `band_bottom`. - - sleep : float, optional - How long to wait in seconds after the resume condition is met - before marking the event as done. Defaults to 0 - - pre_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - - post_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - """ - def _should_resume(self, value): - return self._bot < value < self._top - - def _should_suspend(self, value): - return not (self._bot < value < self._top) - - def _get_justification(self): - if not self.tripped: - return '' - - just = ('Signal {} = {!r} is outside of the range ({}, {})' - ''.format(self._sig.name, self._sig.get(), - self._bot, self._top) - ) - return ': '.join(s for s in (just, self._tripped_message) - if s)
- - -class SuspendInBand(SuspendWhenOutsideBand): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - warn("SuspendInBand has been renamed SuspendWhenOutsideBand to make " - "its meaning more clear. Its behavior has not changed.") - - -class SuspendOutBand(_SuspendBandBase): - """ - Suspend when a scalar signal enters a given band of values. - - This is mostly here because it is the opposite of `SuspenderInBand`. - - Parameters - ---------- - - signal : `ophyd.Signal` - The signal to watch for changes to determine if the - scan should be suspended - - band_bottom, band_top : float - The top and bottom of the band. `band_top` must be - strictly greater than `band_bottom`. - - sleep : float, optional - How long to wait in seconds after the resume condition is met - before marking the event as done. Defaults to 0 - - pre_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - - post_plan : iterable or iterator, optional - a generator, list, or similar containing `Msg` objects - """ - def __init__(self, *args, **kwargs): - warn("bluesky.suspenders.SuspendOutBand is deprecated.") - super().__init__(*args, **kwargs) - - def _should_resume(self, value): - return not (self._bot < value < self._top) - - def _should_suspend(self, value): - return (self._bot < value < self._top) - - def _get_justification(self): - if not self.tripped: - return '' - - just = ('Signal {} = {!r} is inside of the range ({}, {})' - ''.format(self._sig.name, self._sig.get(), - self._bot, self._top) - ) - return ': '.join(s for s in (just, self._tripped_message) - if s) - - -
[docs]class SuspendWhenChanged(SuspenderBase): - """ - Suspend when the monitored value deviates from the expected. - - Only resume if allowed AND when monitored equals expected. - - Notes - ----- - - This suspender is designed to require bluesky restart if value changes. - - USE CASE: - - :class:`~SuspendWhenChanged()` is useful when ``signal`` is an EPICS enumeration - (`"mbbo" <https://wiki-ext.aps.anl.gov/epics/index.php/RRM_3-14_Multi-Bit_Binary_Output>`_) - used with a multi-instrument facility. - Choices predefined in the mbbo record are the - names of instruments allowed to control any shared hardware. - - * The ``signal``, set by instrument staff outside of bluesky, - names which instrument is allowed to control the hardware. - * Other instruments not matching ``signal`` are expected **not** to - control the hardware (they could use simulators instead or not operate - the shared hardware). - - Since a decision of hardware *vs.* simulators is made at the - time a bluesky session starts and ophyd objects are first created, the - session needs to be aware immediately if the ``signal`` is changed. - The default value of ``allow_resume=False`` defends this decision. - If there is a mechanism engineered to toggle ophyd signals between - hardware and simulators, one might consider ``allow_resume=True``. - - - Parameters - ---------- - - signal : `ophyd.Signal` - The signal to watch for changes to determine if the - scan should be suspended - - expected_value : str, float, or int - RunEngine operations will be suspended when signal deviates - from this value. If `None` (default), set to value of - ``signal`` when object is created. - - allow_resume : bool - Should RunEngine be allowed to resume once ``signal.value == expected`` - again? Default value of ``False`` is expected for intended use case. - - sleep : float, optional - How long to wait in seconds after the resume condition is met - before marking the event as done. Defaults to ``0``. - - pre_plan : iterable or callable, optional - Plan to execute just before suspending. If callable, must - take no arguments. - - post_plan : iterable or callable, optional - Plan to execute just before resuming. If callable, must - take no arguments. - - tripped_message : str, optional - Message to include in the trip notification - - - Examples - -------- - - .. code-block:: python - - # pause if this value changes in our session - # note: this suspender is designed to require Bluesky restart if value changes - suspend_instrument_in_use = SuspendWhenChanged(instrument_in_use) - RE.install_suspender(suspend_instrument_in_use) - - Example EPICS database for APS 2-BM-A and 2-BM-B: - - .. code-block:: text - - record(mbbo, "2bm:instrument_in_use") { - # instrument team sets this - # For additional field names, see - # https://epics.anl.gov/EpicsDocumentation/AppDevManuals/RecordRef/Recordref-25.html#HEADING25-15 - field(DESC, "instrument using beam now") - field(ZRST, "none") - field(ONST, "2-BM-A") - field(TWST, "2-BM-B") - # THST - # FRST - # FVST - # ... - } - - NOTE: **Always** make the zero choice (``ZRST``) in the mbbo record to be 'none'. - This allows the instrument staff to designate that *no* instrument is allowed - to control the shared hardware. Start the names of the allowed instruments - with ``ONST``. - - It is convenient for the multi-instrument facility to make this definition - in EPICS rather than in a specific bluesky session. The EPICS value could be - useful in other contexts of instrument control beyond the realm of bluesky. - """ - -
[docs] def __init__(self, signal, *, - expected_value=None, - allow_resume=False, - sleep=0, pre_plan=None, post_plan=None, tripped_message='', - **kwargs): - - self.expected_value = expected_value or signal.value - self.allow_resume = allow_resume - super().__init__(signal, - sleep=sleep, - pre_plan=pre_plan, - post_plan=post_plan, - tripped_message=tripped_message, - **kwargs)
- - def _should_suspend(self, value): - return value != self.expected_value - - def _should_resume(self, value): - return self.allow_resume and value == self.expected_value - - def _get_justification(self): - if not self.tripped: - return '' - - just = ( - f'Signal {self._sig.name}' - f', got "{self._sig.get()}"' - f', expected "{self.expected_value}"' - ) - if not self.allow_resume: - just += '. "RE.abort()" and then restart session to use new configuration.' - return ': '.join( - s - for s in (just, self._tripped_message) - if s)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/bluesky/utils.html b/bluesky/_modules/bluesky/utils.html deleted file mode 100644 index ba8ef8d231..0000000000 --- a/bluesky/_modules/bluesky/utils.html +++ /dev/null @@ -1,1915 +0,0 @@ - - - - - - - - - - bluesky.utils — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • bluesky.utils
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for bluesky.utils

-from collections import namedtuple
-import asyncio
-import os
-import sys
-import signal
-import operator
-import uuid
-from functools import reduce
-from weakref import ref, WeakKeyDictionary
-import types
-import inspect
-from inspect import Parameter, Signature
-import itertools
-import abc
-from collections.abc import Iterable
-import numpy as np
-from cycler import cycler
-import datetime
-from functools import wraps, partial
-import threading
-import time
-from tqdm import tqdm
-from tqdm.utils import _screen_shape_wrapper, _term_move_up, _unicode
-import warnings
-
-import msgpack
-import msgpack_numpy
-import zict
-
-try:
-    # cytools is a drop-in replacement for toolz, implemented in Cython
-    from cytools import groupby
-except ImportError:
-    from toolz import groupby
-
-
-
[docs]class Msg(namedtuple("Msg_base", ["command", "obj", "args", "kwargs", "run"])): - """Namedtuple sub-class to encapsulate a message from the plan to the RE. - - This class provides 3 key features: - - 1. dot access to the contents - 2. default values and a variadic signature for args / kwargs - 3. a nice repr - """ - - __slots__ = () - - def __new__(cls, command, obj=None, *args, run=None, **kwargs): - return super(Msg, cls).__new__(cls, command, obj, args, kwargs, run) - - def __repr__(self): - return (f"Msg({self.command!r}, obj={self.obj!r}, " - f"args={self.args}, kwargs={self.kwargs}, run={self.run!r})")
- - -
[docs]class RunEngineControlException(Exception): - """Exception for signaling within the RunEngine."""
- - -
[docs]class RequestAbort(RunEngineControlException): - """Request that the current run be aborted.""" - - exit_status = 'abort'
- - -
[docs]class RequestStop(RunEngineControlException): - """Request that the current run be stopped and marked successful.""" - - exit_status = 'success'
- - -
[docs]class RunEngineInterrupted(Exception): - pass
- - -
[docs]class NoReplayAllowed(Exception): - pass
- - -
[docs]class IllegalMessageSequence(Exception): - pass
- - -
[docs]class FailedPause(Exception): - pass
- - -
[docs]class FailedStatus(Exception): - """Exception to be raised if a SatusBase object reports done but failed"""
- - -
[docs]class InvalidCommand(KeyError): - pass
- - -
[docs]class PlanHalt(GeneratorExit): - pass
- - -
[docs]class RampFail(RuntimeError): - ...
- - -PLAN_TYPES = (types.GeneratorType,) -try: - from types import CoroutineType -except ImportError: - # < py35 - pass -else: - PLAN_TYPES = PLAN_TYPES + (CoroutineType, ) - del CoroutineType - - -def ensure_generator(plan): - """ - Ensure that the input is a generator. - - Parameters - ---------- - plan : iterable or iterator - - Returns - ------- - gen : coroutine - """ - if isinstance(plan, Msg): - return single_gen(plan) - gen = iter(plan) # no-op on generators; needed for classes - if not isinstance(gen, PLAN_TYPES): - # If plan does not support .send, we must wrap it in a generator. - gen = (msg for msg in gen) - - return gen - - -
[docs]def single_gen(msg): - '''Turn a single message into a plan - - If ``lambda x: yield x`` were valid Python, this would be equivalent. - In Python 3.6 or 3.7 we might get lambda generators. - - Parameters - ---------- - msg : Msg - a single message - - Yields - ------ - msg : Msg - the input message - ''' - return (yield msg)
- - -class SignalHandler: - """Context manager for signal handing - - If multiple signals come in quickly, they may not all be seen, quoting - the libc manual: - - Remember that if there is a particular signal pending for your - process, additional signals of that same type that arrive in the - meantime might be discarded. For example, if a SIGINT signal is - pending when another SIGINT signal arrives, your program will - probably only see one of them when you unblock this signal. - - https://www.gnu.org/software/libc/manual/html_node/Checking-for-Pending-Signals.html - """ - def __init__(self, sig, log=None): - self.sig = sig - self.interrupted = False - self.count = 0 - self.log = log - - def __enter__(self): - self.interrupted = False - self.released = False - self.count = 0 - - self.original_handler = signal.getsignal(self.sig) - - def handler(signum, frame): - self.interrupted = True - self.count += 1 - if self.log is not None: - self.log.debug('SignalHandler caught SIGINT; count is %r', - self.count) - if self.count > 10: - orig_func = self.original_handler - self.release() - orig_func(signum, frame) - - self.handle_signals() - - signal.signal(self.sig, handler) - return self - - def __exit__(self, type, value, tb): - self.release() - - def release(self): - if self.released: - return False - signal.signal(self.sig, self.original_handler) - self.released = True - return True - - def handle_signals(self): - ... - - -class SigintHandler(SignalHandler): - def __init__(self, RE): - super().__init__(signal.SIGINT, log=RE.log) - self.RE = RE - self.last_sigint_time = None # time most recent SIGINT was processed - self.num_sigints_processed = 0 # count SIGINTs processed - - def __enter__(self): - return super().__enter__() - - def handle_signals(self): - # Check for pause requests from keyboard. - # TODO, there is a possible race condition between the two - # pauses here - if self.RE.state.is_running and (not self.RE._interrupted): - if (self.last_sigint_time is None or - time.time() - self.last_sigint_time > 10): - # reset the counter to 1 - # It's been 10 seconds since the last SIGINT. Reset. - self.count = 1 - if self.last_sigint_time is not None: - self.log.debug("It has been 10 seconds since the " - "last SIGINT. Resetting SIGINT " - "handler.") - # weeee push these to threads to not block the main thread - threading.Thread(target=self.RE.request_pause, - args=(True,)).start() - print("A 'deferred pause' has been requested. The " - "RunEngine will pause at the next checkpoint. " - "To pause immediately, hit Ctrl+C again in the " - "next 10 seconds.") - - self.last_sigint_time = time.time() - elif self.count == 2: - print('trying a second time') - # - Ctrl-C twice within 10 seconds -> hard pause - self.log.debug("RunEngine detected two SIGINTs. " - "A hard pause will be requested.") - - threading.Thread(target=self.RE.request_pause, - args=(False,)).start() - self.last_sigint_time = time.time() - - -class CallbackRegistry: - """ - See matplotlib.cbook.CallbackRegistry. This is a simplified since - ``bluesky`` is python3.4+ only! - """ - def __init__(self, ignore_exceptions=False, allowed_sigs=None): - self.ignore_exceptions = ignore_exceptions - self.allowed_sigs = allowed_sigs - self.callbacks = dict() - self._cid = 0 - self._func_cid_map = {} - - def __getstate__(self): - # We cannot currently pickle the callables in the registry, so - # return an empty dictionary. - return {} - - def __setstate__(self, state): - # re-initialise an empty callback registry - self.__init__() - - def connect(self, sig, func): - """Register ``func`` to be called when ``sig`` is generated - - Parameters - ---------- - sig - func - - Returns - ------- - cid : int - The callback index. To be used with ``disconnect`` to deregister - ``func`` so that it will no longer be called when ``sig`` is - generated - """ - if self.allowed_sigs is not None: - if sig not in self.allowed_sigs: - raise ValueError("Allowed signals are {0}".format( - self.allowed_sigs)) - self._func_cid_map.setdefault(sig, WeakKeyDictionary()) - # Note proxy not needed in python 3. - # TODO rewrite this when support for python2.x gets dropped. - # Following discussion with TC: weakref.WeakMethod can not be used to - # replace the custom 'BoundMethodProxy', because it does not accept - # the 'destroy callback' as a parameter. The 'destroy callback' is - # necessary to automatically unsubscribe CB registry from the callback - # when the class object is destroyed and this is the main purpose of - # BoundMethodProxy. - proxy = _BoundMethodProxy(func) - if proxy in self._func_cid_map[sig]: - return self._func_cid_map[sig][proxy] - - proxy.add_destroy_callback(self._remove_proxy) - self._cid += 1 - cid = self._cid - self._func_cid_map[sig][proxy] = cid - self.callbacks.setdefault(sig, dict()) - self.callbacks[sig][cid] = proxy - return cid - - def _remove_proxy(self, proxy): - # need the list because `del self._func_cid_map[sig]` mutates the dict - for sig, proxies in list(self._func_cid_map.items()): - try: - # Here we need to delete the last reference to proxy (in 'self.callbacks[sig]') - # The respective entries in 'self._func_cid_map' are deleted automatically, - # since 'self._func_cid_map[sig]' entries are WeakKeyDictionary objects. - del self.callbacks[sig][proxies[proxy]] - except KeyError: - pass - - # Remove dictionary items for signals with no assigned callbacks - if len(self.callbacks[sig]) == 0: - del self.callbacks[sig] - del self._func_cid_map[sig] - - def disconnect(self, cid): - """Disconnect the callback registered with callback id *cid* - - Parameters - ---------- - cid : int - The callback index and return value from ``connect`` - """ - for eventname, callbackd in self.callbacks.items(): - try: - # This may or may not remove entries in 'self._func_cid_map'. - del callbackd[cid] - except KeyError: - continue - else: - # Look for cid in 'self._func_cid_map' as well. It may still be there. - for sig, functions in self._func_cid_map.items(): - for function, value in list(functions.items()): - if value == cid: - del functions[function] - return - - def process(self, sig, *args, **kwargs): - """Process ``sig`` - - All of the functions registered to receive callbacks on ``sig`` - will be called with ``args`` and ``kwargs`` - - Parameters - ---------- - sig - args - kwargs - """ - if self.allowed_sigs is not None: - if sig not in self.allowed_sigs: - raise ValueError("Allowed signals are {0}".format( - self.allowed_sigs)) - exceptions = [] - if sig in self.callbacks: - for cid, func in list(self.callbacks[sig].items()): - try: - func(*args, **kwargs) - except ReferenceError: - self._remove_proxy(func) - except Exception as e: - if self.ignore_exceptions: - exceptions.append((e, sys.exc_info()[2])) - else: - raise - return exceptions - - -class _BoundMethodProxy: - ''' - Our own proxy object which enables weak references to bound and unbound - methods and arbitrary callables. Pulls information about the function, - class, and instance out of a bound method. Stores a weak reference to the - instance to support garbage collection. - @organization: IBM Corporation - @copyright: Copyright (c) 2005, 2006 IBM Corporation - @license: The BSD License - Minor bugfixes by Michael Droettboom - ''' - def __init__(self, cb): - self._hash = hash(cb) - self._destroy_callbacks = [] - try: - # This branch is successful if 'cb' bound method and class method, - # but destroy_callback mechanism works only for bound methods, - # since cb.__self__ points to class instance only for - # bound methods, not for class methods. Therefore destroy_callback - # will not be called for class methods. - try: - self.inst = ref(cb.__self__, self._destroy) - except TypeError: - self.inst = None - self.func = cb.__func__ - self.klass = cb.__self__.__class__ - - except AttributeError: - # 'cb' is a function, callable object or static method. - # No weak reference is created, strong reference is stored instead. - self.inst = None - self.func = cb - self.klass = None - - def add_destroy_callback(self, callback): - self._destroy_callbacks.append(_BoundMethodProxy(callback)) - - def _destroy(self, wk): - for callback in self._destroy_callbacks: - try: - callback(self) - except ReferenceError: - pass - - def __getstate__(self): - d = self.__dict__.copy() - # de-weak reference inst - inst = d['inst'] - if inst is not None: - d['inst'] = inst() - return d - - def __setstate__(self, statedict): - self.__dict__ = statedict - inst = statedict['inst'] - # turn inst back into a weakref - if inst is not None: - self.inst = ref(inst) - - def __call__(self, *args, **kwargs): - ''' - Proxy for a call to the weak referenced object. Take - arbitrary params to pass to the callable. - Raises `ReferenceError`: When the weak reference refers to - a dead object - ''' - if self.inst is not None and self.inst() is None: - raise ReferenceError - elif self.inst is not None: - # build a new instance method with a strong reference to the - # instance - - mtd = types.MethodType(self.func, self.inst()) - - else: - # not a bound method, just return the func - mtd = self.func - # invoke the callable and return the result - return mtd(*args, **kwargs) - - def __eq__(self, other): - ''' - Compare the held function and instance with that held by - another proxy. - ''' - try: - if self.inst is None: - return self.func == other.func and other.inst is None - else: - return self.func == other.func and self.inst() == other.inst() - except Exception: - return False - - def __ne__(self, other): - ''' - Inverse of __eq__. - ''' - return not self.__eq__(other) - - def __hash__(self): - return self._hash - - -# The following two code blocks are adapted from David Beazley's -# 'Python 3 Metaprogramming' https://www.youtube.com/watch?v=sPiWg5jSoZI - - -class StructMeta(type): - def __new__(cls, name, bases, clsdict): - clsobj = super().__new__(cls, name, bases, clsdict) - args_params = [Parameter(name, Parameter.POSITIONAL_OR_KEYWORD) - for name in clsobj._fields] - kwargs_params = [Parameter(name, Parameter.KEYWORD_ONLY, default=None) - for name in ['md']] - sig = Signature(args_params + kwargs_params) - setattr(clsobj, '__signature__', sig) - return clsobj - - -class Struct(metaclass=StructMeta): - "The _fields of any subclass become its attritubes and __init__ args." - _fields = [] - - def __init__(self, *args, **kwargs): - # Now bind default values of optional arguments. - # If it seems like there should be a cleaner way to do this, see - # http://bugs.python.org/msg221104 - bound = self.__signature__.bind(*args, **kwargs) - for name, param in self.__signature__.parameters.items(): - if (name not in bound.arguments and - param.default is not inspect._empty): - bound.arguments[name] = param.default - for name, val in bound.arguments.items(): - setattr(self, name, val) - self.flyers = [] - - def set(self, **kwargs): - "Update attributes as keyword arguments." - for attr, val in kwargs.items(): - setattr(self, attr, val) - - -SUBS_NAMES = ['all', 'start', 'stop', 'event', 'descriptor'] - - -def normalize_subs_input(subs): - "Accept a callable, a list, or a dict. Normalize to a dict of lists." - normalized = {name: [] for name in SUBS_NAMES} - if subs is None: - pass - elif callable(subs): - normalized['all'].append(subs) - elif hasattr(subs, 'items'): - for key, funcs in list(subs.items()): - if key not in SUBS_NAMES: - raise KeyError("Keys must be one of {!r:0}".format(SUBS_NAMES)) - if callable(funcs): - normalized[key].append(funcs) - else: - normalized[key].extend(funcs) - elif isinstance(subs, Iterable): - normalized['all'].extend(subs) - else: - raise ValueError("Subscriptions should be a callable, a list of " - "callables, or a dictionary mapping subscription " - "names to lists of callables.") - # Validates that all entries are callables. - for name, funcs in normalized.items(): - for func in funcs: - if not callable(func): - raise ValueError("subs values must be functions or lists " - "of functions. The offending entry is\n " - "{0}".format(func)) - return normalized - - -class DefaultSubs: - """a class-level descriptor""" - def __init__(self, default=None): - self._value = normalize_subs_input(default) - - def __get__(self, instance, owner): - return self._value - - def __set__(self, instance, value): - self._value = normalize_subs_input(value) - - -class Subs: - """a 'reusable' property""" - def __init__(self, default=None): - self.default = normalize_subs_input(default) - self.data = WeakKeyDictionary() - - def __get__(self, instance, owner): - return self.data.get(instance, self.default) - - def __set__(self, instance, value): - self.data[instance] = normalize_subs_input(value) - - -def snake_cyclers(cyclers, snake_booleans): - """ - Combine cyclers with a 'snaking' back-and-forth order. - - Parameters - ---------- - cyclers : cycler.Cycler - or any iterable that yields dictionaries of lists - snake_booleans : list - a list of the same length as cyclers indicating whether each cycler - should 'snake' (True) or not (False). Note that the first boolean - does not make a difference because the first (slowest) dimension - does not repeat. - - Returns - ------- - result : cycler - """ - if len(cyclers) != len(snake_booleans): - raise ValueError("number of cyclers does not match number of booleans") - lengths = [] - new_cyclers = [] - for c in cyclers: - lengths.append(len(c)) - total_length = np.product(lengths) - for i, (c, snake) in enumerate(zip(cyclers, snake_booleans)): - num_tiles = np.product(lengths[:i]) - num_repeats = np.product(lengths[i+1:]) - for k, v in c._transpose().items(): - if snake: - v = v + v[::-1] - v2 = np.tile(np.repeat(v, num_repeats), num_tiles) - expanded = v2[:total_length] - new_cyclers.append(cycler(k, expanded)) - return reduce(operator.add, new_cyclers) - - -def first_key_heuristic(device): - """ - Get the fully-qualified data key for the first entry in describe(). - - This will raise is that entry's `describe()` method does not return a - dictionary with exactly one key. - """ - return next(iter(device.describe())) - - -def ancestry(obj): - """ - List self, parent, grandparent, ... back to ultimate ancestor. - - Parameters - ---------- - obj : object - must have a `parent` attribute - - Returns - ------- - ancestry : list - list of objects, starting with obj and tracing parents recursively - """ - ancestry = [] - ancestor = obj - while True: - ancestry.append(ancestor) - if ancestor.parent is None: - return ancestry - ancestor = ancestor.parent - - -def root_ancestor(obj): - """ - Traverse ancestry to obtain root ancestor. - - Parameters - ---------- - obj : object - must have a `parent` attribute - - Returns - ------- - root : object - """ - return ancestry(obj)[-1] - - -def share_ancestor(obj1, obj2): - """ - Check whether obj1 and obj2 have a common ancestor. - - Parameters - ---------- - obj1 : object - must have a `parent` attribute - obj2 : object - must have a `parent` attribute - - Returns - ------- - result : boolean - """ - return ancestry(obj1)[-1] is ancestry(obj2)[-1] - - -def separate_devices(devices): - """ - Filter out elements that have other elements as their ancestors. - - If A is an ancestor of B, [A, B, C] -> [A, C]. - - Paremeters - ---------- - devices : list - All elements must have a `parent` attribute. - - Returns - ------- - result : list - subset of input, with order retained - """ - result = [] - for det in devices: - for existing_det in result[:]: - if existing_det in ancestry(det): - # known issue: here we assume that det is in the read_attrs - # of existing_det -- to be addressed after plans.py refactor - break - elif det in ancestry(existing_det): - # existing_det is redundant; use det in its place - result.remove(existing_det) - else: - result.append(det) - return result - - -def all_safe_rewind(devices): - '''If all devices can have their trigger method re-run on resume. - - Parameters - ---------- - devices : list - List of devices - - Returns - ------- - safe_rewind : bool - If all the device can safely re-triggered - ''' - for d in devices: - if hasattr(d, 'rewindable'): - rewindable = d.rewindable.get() - if not rewindable: - return False - return True - - -
[docs]class PersistentDict(zict.Func): - """ - A MutableMapping which syncs it contents to disk. - - The contents are stored as msgpack-serialized files, with one file per item - in the mapping. - - Note that when an item is *mutated* it is not immediately synced: - - >>> d['sample'] = {"color": "red"} # immediately synced - >>> d['sample']['shape'] = 'bar' # not immediately synced - - but that the full contents are synced to disk when the PersistentDict - instance is garbage collected. - """ -
[docs] def __init__(self, directory): - self._directory = directory - self._file = zict.File(directory) - self._cache = {} - super().__init__(self._dump, self._load, self._file) - self.reload() - - # Similar to flush() or _do_update(), but without reference to self - # to avoid circular reference preventing collection. - # NOTE: This still doesn't guarantee call on delete or gc.collect()! - # Explicitly call flush() if immediate write to disk required. - def finalize(zfile, cache, dump): - zfile.update((k, dump(v)) for k, v in cache.items()) - - import weakref - self._finalizer = weakref.finalize( - self, finalize, self._file, self._cache, PersistentDict._dump)
- - @property - def directory(self): - return self._directory - - def __setitem__(self, key, value): - self._cache[key] = value - super().__setitem__(key, value) - - def __getitem__(self, key): - return self._cache[key] - - def __delitem__(self, key): - del self._cache[key] - super().__delitem__(key) - - def __repr__(self): - return f"<{self.__class__.__name__} {dict(self)!r}>" - - @staticmethod - def _dump(obj): - "Encode as msgpack using numpy-aware encoder." - # See https://github.com/msgpack/msgpack-python#string-and-binary-type - # for more on use_bin_type. - return msgpack.packb( - obj, - default=msgpack_numpy.encode, - use_bin_type=True) - - @staticmethod - def _load(file): - return msgpack.unpackb( - file, - object_hook=msgpack_numpy.decode, - raw=False) - - def flush(self): - """Force a write of the current state to disk""" - for k, v in self.items(): - super().__setitem__(k, v) - - def reload(self): - """Force a reload from disk, overwriting current cache""" - self._cache = dict(super().items())
- - -SEARCH_PATH = [] -ENV_VAR = 'BLUESKY_HISTORY_PATH' -if ENV_VAR in os.environ: - SEARCH_PATH.append(os.environ[ENV_VAR]) -SEARCH_PATH.extend([os.path.expanduser('~/.config/bluesky/bluesky_history.db'), - '/etc/bluesky/bluesky_history.db']) - - -def get_history(): - """ - DEPRECATED: Return a dict-like object for stashing metadata. - - If historydict is not installed, return a dict. - - If historydict is installed, look for a sqlite file in: - - $BLUESKY_HISTORY_PATH, if defined - - ~/.config/bluesky/bluesky_history.db - - /etc/bluesky/bluesky_history.db - - If no existing file is found, create a new sqlite file in: - - $BLUESKY_HISTORY_PATH, if defined - - ~/.config/bluesky/bluesky_history.db, otherwise - """ - try: - import historydict - except ImportError: - print("You do not have historydict installed, your metadata " - "will not be persistent or have any history of the " - "values.") - return dict() - else: - for path in SEARCH_PATH: - if os.path.isfile(path): - print("Loading metadata history from %s" % path) - return historydict.HistoryDict(path) - # No existing file was found. Try creating one. - path = SEARCH_PATH[0] - try: - os.makedirs(os.path.dirname(path), exist_ok=True) - print("Storing metadata history in a new file at %s." % path) - return historydict.HistoryDict(path) - except IOError as exc: - print(exc) - print("Failed to create metadata history file at %s" % path) - print("Storing HistoryDict in memory; it will not persist " - "when session is ended.") - return historydict.HistoryDict(':memory:') - - -_QT_KICKER_INSTALLED = {} -_NB_KICKER_INSTALLED = {} - - -
[docs]def install_kicker(loop=None, update_rate=0.03): - """ - Install a periodic callback to integrate drawing and asyncio event loops. - - This dispatches to :func:`install_qt_kicker` or :func:`install_nb_kicker` - depending on the current matplotlib backend. - - Parameters - ---------- - loop : event loop, optional - update_rate : number - Seconds between periodic updates. Default is 0.03. - """ - import matplotlib - backend = matplotlib.get_backend() - if backend == 'nbAgg': - install_nb_kicker(loop=loop, update_rate=update_rate) - elif backend in ('Qt4Agg', 'Qt5Agg'): - install_qt_kicker(loop=loop, update_rate=update_rate) - else: - raise NotImplementedError("The matplotlib backend {} is not yet " - "supported.".format(backend))
- - -
[docs]def install_qt_kicker(loop=None, update_rate=0.03): - """Install a periodic callback to integrate Qt and asyncio event loops. - - DEPRECATED: This functionality is now handled automatically by default and - is configurable via the RunEngine's new ``during_task`` parameter. Calling - this function now has no effect. It will be removed in a future release of - bluesky. - - Parameters - ---------- - loop : event loop, optional - update_rate : number - Seconds between periodic updates. Default is 0.03. - """ - warnings.warn("bluesky.utils.install_qt_kicker is no longer necessary and " - "has no effect. Please remove your use of it. It may be " - "removed in a future release of bluesky.")
- - -
[docs]def install_nb_kicker(loop=None, update_rate=0.03): - """ - Install a periodic callback to integrate ipykernel and asyncio event loops. - - It is safe to call this function multiple times. - - Parameters - ---------- - loop : event loop, optional - update_rate : number - Seconds between periodic updates. Default is 0.03. - """ - import matplotlib - if loop is None: - loop = asyncio.get_event_loop() - global _NB_KICKER_INSTALLED - if loop in _NB_KICKER_INSTALLED: - return - - def _nbagg_kicker(): - # This is more brute-force variant of the _qt_kicker function used - # inside install_qt_kicker. - for f_mgr in matplotlib._pylab_helpers.Gcf.get_all_fig_managers(): - if f_mgr.canvas.figure.stale: - f_mgr.canvas.draw() - - loop.call_later(update_rate, _nbagg_kicker) - - _NB_KICKER_INSTALLED[loop] = loop.call_soon(_nbagg_kicker)
- - -def apply_sub_factories(factories, plan): - '''Run sub factory functions for a plan - - Factory functions should return lists, which will be added onto the - subscription key (e.g., 'all' or 'start') specified in the factory - definition. - - If the factory function returns None, the list will not be modified. - ''' - factories = normalize_subs_input(factories) - out = {k: list(itertools.filterfalse(lambda x: x is None, - (sf(plan) for sf in v))) - for k, v in factories.items()} - return out - - -def update_sub_lists(out, inp): - """Extends dictionary `out` lists with those in `inp` - - Assumes dictionaries where all values are lists - """ - for k, v in inp.items(): - try: - out[k].extend(v) - except KeyError: - out[k] = list(v) - - -def register_transform(RE, *, prefix='<', ip=None): - '''Register RunEngine IPython magic convenience transform - Assuming the default parameters - This maps `< stuff(*args, **kwargs)` -> `RE(stuff(*args, **kwargs))` - RE is assumed to be available in the global namespace - Parameters - ---------- - RE : str - The name of a valid RunEngine instance in the global IPython namespace - prefix : str, optional - The prefix to trigger this transform on. If this collides with - valid python syntax or an existing transform you are on your own. - ip : IPython shell, optional - If not passed, uses `IPython.get_ipython()` to get the current shell - ''' - import IPython - - if ip is None: - ip = IPython.get_ipython() - - if IPython.__version__ >= '7': - def tr_re(lines): - if len(lines) != 1: - return lines - line, = lines - head, split, tail = line.partition(prefix) - if split == prefix and head.strip() == '': - line = f'{RE}({tail.strip()})\n' - - return [line] - - ip.input_transformers_post.append(tr_re) - - else: - from IPython.core.inputtransformer import StatelessInputTransformer - - @StatelessInputTransformer.wrap - def tr_re(line): - if line.startswith(prefix): - line = line[len(prefix):].strip() - return '{}({})'.format(RE, line) - return line - - ip.input_splitter.logical_line_transforms.append(tr_re()) - ip.input_transformer_manager.logical_line_transforms.append(tr_re()) - - -class AsyncInput: - """a input prompt that allows event loop to run in the background - - adapted from http://stackoverflow.com/a/35514777/1221924 - """ - def __init__(self, loop=None): - self.loop = loop or asyncio.get_event_loop() - self.q = asyncio.Queue(loop=self.loop) - self.loop.add_reader(sys.stdin, self.got_input) - - def got_input(self): - asyncio.ensure_future(self.q.put(sys.stdin.readline()), loop=self.loop) - - async def __call__(self, prompt, end='\n', flush=False): - print(prompt, end=end, flush=flush) - return (await self.q.get()).rstrip('\n') - - -def new_uid(): - return str(uuid.uuid4()) - - -def sanitize_np(val): - "Convert any numpy objects into built-in Python types." - if isinstance(val, (np.generic, np.ndarray)): - if np.isscalar(val): - return val.item() - return val.tolist() - return val - - -def expiring_function(func, loop, *args, **kwargs): - """ - If timeout has not occurred, call func(*args, **kwargs). - - This is meant to used with the event loop's run_in_executor - method. Outside that context, it doesn't make any sense. - """ - def dummy(start_time, timeout): - if loop.time() > start_time + timeout: - return - func(*args, **kwargs) - return - - return dummy - - -def short_uid(label=None, truncate=6): - "Return a readable but unique id like 'label-fjfi5a'" - if label: - return '-'.join([label, new_uid()[:truncate]]) - else: - return new_uid()[:truncate] - - -def ensure_uid(doc_or_uid): - """ - Accept a uid or a dict with a 'uid' key. Return the uid. - """ - try: - return doc_or_uid['uid'] - except TypeError: - return doc_or_uid - - -def ts_msg_hook(msg, file=sys.stdout): - t = '{:%H:%M:%S.%f}'.format(datetime.datetime.now()) - msg_fmt = "{: <17s} -> {!s: <15s} args: {}, kwargs: {}, run: {}".format( - msg.command, - msg.obj.name if hasattr(msg.obj, 'name') else msg.obj, - msg.args, - msg.kwargs, - "'{}'".format(msg.run) if isinstance(msg.run, str) else msg.run) - print('{} {}'.format(t, msg_fmt), file=file) - - -
[docs]def make_decorator(wrapper): - """ - Turn a generator instance wrapper into a generator function decorator. - - The functions named <something>_wrapper accept a generator instance and - return a mutated generator instance. - - Example of a 'wrapper': - >>> plan = count([det]) # returns a generator instance - >>> revised_plan = some_wrapper(plan) # returns a new instance - - Example of a decorator: - >>> some_decorator = make_decorator(some_wrapper) # returns decorator - >>> customized_count = some_decorator(count) # returns generator func - >>> plan = customized_count([det]) # returns a generator instance - - This turns a 'wrapper' into a decorator, which accepts a generator - function and returns a generator function. - """ - @wraps(wrapper) - def dec_outer(*args, **kwargs): - def dec(gen_func): - @wraps(gen_func) - def dec_inner(*inner_args, **inner_kwargs): - plan = gen_func(*inner_args, **inner_kwargs) - plan = wrapper(plan, *args, **kwargs) - return (yield from plan) - return dec_inner - return dec - return dec_outer
- - -def apply_to_dict_recursively(d, f): - """Recursively apply function to a document - - This modifies the dict in place and returns it. - - Parameters - ---------- - d: dict - e.g. event_model Document - f: function - any func to be performed on d recursively - """ - for key, val in d.items(): - if hasattr(val, 'items'): - d[key] = apply_to_dict_recursively(d=val, f=f) - d[key] = f(val) - return d - - -
[docs]class ProgressBar: -
[docs] def __init__(self, status_objs, delay_draw=0.2): - """ - Represent status objects with a progress bars. - - Parameters - ---------- - status_objs : list - Status objects - delay_draw : float, optional - To avoid flashing progress bars that will complete quickly after - they are displayed, delay drawing until the progress bar has been - around for awhile. Default is 0.2 seconds. - """ - self.meters = [] - self.status_objs = [] - # Determine terminal width. - self.ncols = _screen_shape_wrapper()(sys.stdout)[0] or 79 - self.fp = sys.stdout - self.creation_time = time.time() - self.delay_draw = delay_draw - self.drawn = False - self.done = False - self.lock = threading.RLock() - - # If the ProgressBar is not finished before the delay_draw time but - # never again updated after the delay_draw time, we need to draw it - # once. - if delay_draw: - threading.Thread(target=self._ensure_draw, daemon=True).start() - - # Create a closure over self.update for each status object that - # implemets the 'watch' method. - for st in status_objs: - with self.lock: - if hasattr(st, 'watch') and not st.done: - pos = len(self.meters) - self.meters.append('') - self.status_objs.append(st) - st.watch(partial(self.update, pos))
- -
[docs] def update(self, pos, *, - name=None, - current=None, initial=None, target=None, - unit='units', precision=None, - fraction=None, - time_elapsed=None, time_remaining=None): - if all(x is not None for x in (current, initial, target)): - # Display a proper progress bar. - total = round(_L2norm(target, initial), precision or 3) - # make sure we ignore overshoot to prevent tqdm from exploding. - n = np.clip(round(_L2norm(current, initial), precision or 3), 0, total) - # Compute this only if the status object did not provide it. - if time_elapsed is None: - time_elapsed = time.time() - self.creation_time - # TODO Account for 'fraction', which might in some special cases - # differ from the naive computation above. - # TODO Account for 'time_remaining' which might in some special - # cases differ from the naive computaiton performed by - # format_meter. - meter = tqdm.format_meter(n=n, total=total, elapsed=time_elapsed, - unit=unit, - prefix=name, - ncols=self.ncols) - else: - # Simply display completeness. - if name is None: - name = '' - if self.status_objs[pos].done: - meter = name + ' [Complete.]' - else: - meter = name + ' [In progress. No progress bar available.]' - meter += ' ' * (self.ncols - len(meter)) - meter = meter[:self.ncols] - - self.meters[pos] = meter - self.draw()
- -
[docs] def draw(self): - with self.lock: - if (time.time() - self.creation_time) < self.delay_draw: - return - if self.done: - return - for meter in self.meters: - tqdm.status_printer(self.fp)(meter) - self.fp.write('\n') - self.fp.write(_unicode(_term_move_up() * len(self.meters))) - self.drawn = True
- - def _ensure_draw(self): - # Ensure that the progress bar is drawn at least once after the delay. - time.sleep(self.delay_draw) - with self.lock: - if (not self.done) and (not self.drawn): - self.draw() - -
[docs] def clear(self): - with self.lock: - self.done = True - if self.drawn: - for meter in self.meters: - self.fp.write('\r') - self.fp.write(' ' * self.ncols) - self.fp.write('\r') - self.fp.write('\n') - self.fp.write(_unicode(_term_move_up() * len(self.meters)))
- - -
[docs]class ProgressBarManager: -
[docs] def __init__(self, delay_draw=0.2): - self.delay_draw = delay_draw - self.pbar = None
- - def __call__(self, status_objs_or_none): - if status_objs_or_none is not None: - # Start a new ProgressBar. - if self.pbar is not None: - warnings.warn("Previous ProgressBar never competed.") - self.pbar.clear() - self.pbar = ProgressBar(status_objs_or_none, - delay_draw=self.delay_draw) - else: - # Clean up an old one. - if self.pbar is None: - warnings.warn("There is no Progress bar to clean up.") - else: - self.pbar.clear() - self.pbar = None
- - -def _L2norm(x, y): - "works on (3, 5) and ((0, 3), (4, 0))" - return np.sqrt(np.sum((np.asarray(x) - np.asarray(y))**2)) - - -def merge_axis(objs): - '''Merge possibly related axis - - This function will take a list of objects and separate it into - - - list of completely independent objects (most settable things and - detectors) that do not have coupled motion. - - list of devices who have children who are coupled (PseudoPositioner - ducked by looking for 'RealPosition' as an attribute) - - Both of these lists will only contain objects directly passed in - in objs - - - map between parents and objects passed in. Each value - of the map is a map between the strings - {'real', 'pseudo', 'independent'} and a list of objects. All - of the objects in the (doubly nested) map are in the input. - - Parameters - ---------- - objs : Iterable[OphydObj] - The input devices - - Returns - ------- - independent_objs : List[OphydObj] - Independent 'simple' axis - - complex_objs : List[PseudoPositioner] - Independent objects which have interdependent children - - coupled : Dict[PseudoPositioner, Dict[str, List[OphydObj]]] - Mapping of interdependent axis passed in. - ''' - def get_parent(o): - return getattr(o, 'parent') - - independent_objs = set() - maybe_coupled = set() - complex_objs = set() - for o in objs: - parent = o.parent - if hasattr(o, 'RealPosition'): - complex_objs.add(o) - elif (parent is not None and hasattr(parent, 'RealPosition')): - maybe_coupled.add(o) - else: - independent_objs.add(o) - coupled = {} - - for parent, children in groupby(get_parent, maybe_coupled).items(): - real_p = set(parent.real_positioners) - pseudo_p = set(parent.pseudo_positioners) - type_map = {'real': [], 'pseudo': [], 'unrelated': []} - for c in children: - if c in real_p: - type_map['real'].append(c) - elif c in pseudo_p: - type_map['pseudo'].append(c) - else: - type_map['unrelated'].append(c) - coupled[parent] = type_map - - return (independent_objs, complex_objs, coupled) - - -def merge_cycler(cyc): - """Specify movements of sets of interdependent axes atomically. - - Inspect the keys of ``cyc`` (which are Devices) to indentify those - which are interdependent (part of the same - PseudoPositioner) and merge those independent entries into - a single entry. - - This also validates that the user has not passed conflicting - interdependent axis (such as a real and pseudo axis from the same - PseudoPositioner) - - Parameters - ---------- - cyc : Cycler[OphydObj, Sequence] - A cycler as would be passed to :func:`scan_nd` - - Returns - ------- - Cycler[OphydObj, Sequence] - A cycler as would be passed to :func:`scan_nd` with the same - or fewer keys than the input. - - """ - def my_name(obj): - """Get the attribute name of this device on its parent Device - """ - parent = obj.parent - return next(iter([nm for nm in parent.component_names - if getattr(parent, nm) is obj])) - - io, co, gb = merge_axis(cyc.keys) - - # only simple non-coupled objects, declare victory and bail! - if len(co) == len(gb) == 0: - return cyc - - input_data = cyc.by_key() - output_data = [cycler(i, input_data[i]) for i in io | co] - - for parent, type_map in gb.items(): - - if parent in co and (type_map['pseudo'] or type_map['real']): - raise ValueError("A PseudoPostiioner and its children were both " - "passed in. We do not yet know how to merge " - "these inputs, failing.") - - if type_map['real'] and type_map['pseudo']: - raise ValueError("Passed in a mix of real and pseudo axis. " - "Can not cope, failing") - pseudo_axes = type_map['pseudo'] - if len(pseudo_axes) > 1: - p_cyc = reduce(operator.add, - (cycler(my_name(c), input_data[c]) - for c in type_map['pseudo'])) - output_data.append(cycler(parent, list(p_cyc))) - elif len(pseudo_axes) == 1: - c, = pseudo_axes - output_data.append(cycler(c, input_data[c])) - - for c in type_map['real'] + type_map['unrelated']: - output_data.append(cycler(c, input_data[c])) - - return reduce(operator.add, output_data) - - -_qapp = None - - -
[docs]class DuringTask: - """This class waits on the event (which fully blocks the thread).""" - -
[docs] def __init__(self): - pass
- -
[docs] def block(self, blocking_event): - """ - Wait plan to finish. - - Parameters - ---------- - blocking_event : threading.Event - - """ - blocking_event.wait()
- - -
[docs]class DefaultDuringTask(DuringTask): - """This class run the Qt main loop while waiting for the plan to finish. - - The default setting for the RunEngine's during_task parameter. - - This makes it possible for plots that use Matplotlib's Qt backend to update - live during data acquisition. - - It solves the problem that Qt must be run from the main thread. - If Matplotlib and a known Qt binding are already imported, run - Matplotlib qApp until the task completes. If not, there is no need to - handle qApp: just wait on the task. - - """ - -
[docs] def __init__(self): - """ - Initialize backend. - - Currently only the Qt backend is supported. The function is - initializing the 'teleporter' if Qt backend is used. - - """ - if 'matplotlib' in sys.modules: - import matplotlib - backend = matplotlib.get_backend().lower() - if 'qt' in backend: - from .callbacks.mpl_plotting import initialize_qt_teleporter - initialize_qt_teleporter()
- - def block(self, blocking_event): - # docstring inherited - global _qapp - if 'matplotlib' not in sys.modules: - # We are not using matplotlib + Qt. Just wait on the Event. - blocking_event.wait() - # Figure out if we are using matplotlib with which backend - # without importing anything that is not already imported. - else: - import matplotlib - backend = matplotlib.get_backend().lower() - # if with a Qt backend, do the scary thing - if 'qt' in backend: - - from matplotlib.backends.qt_compat import QtCore, QtWidgets - app = QtWidgets.QApplication.instance() - if app is None: - _qapp = app = QtWidgets.QApplication([b'bluesky']) - assert app is not None - event_loop = QtCore.QEventLoop() - - def start_killer_thread(): - def exit_loop(): - blocking_event.wait() - # If the above wait ends quickly, we need to avoid the race - # condition where this thread might try to exit the qApp - # before it even starts. Therefore, we use QTimer, below, - # which will not start running until the qApp event loop is - # running. - event_loop.exit() - - threading.Thread(target=exit_loop).start() - - # https://www.riverbankcomputing.com/pipermail/pyqt/2015-March/035674.html - # adapted from code at - # https://bitbucket.org/tortoisehg/thg/commits/550e1df5fbad - if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'): - # Wake up Python interpreter via pipe so that SIGINT - # can be handled immediately. - # (http://qt-project.org/doc/qt-4.8/unix-signals.html) - # Updated docs: - # https://doc.qt.io/qt-5/unix-signals.html - import fcntl - rfd, wfd = os.pipe() - for fd in (rfd, wfd): - flags = fcntl.fcntl(fd, fcntl.F_GETFL) - fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) - wakeupsn = QtCore.QSocketNotifier(rfd, - QtCore.QSocketNotifier.Read) - origwakeupfd = signal.set_wakeup_fd(wfd) - - def cleanup(): - wakeupsn.setEnabled(False) - rfd = wakeupsn.socket() - wfd = signal.set_wakeup_fd(origwakeupfd) - os.close(int(rfd)) - os.close(wfd) - - def handleWakeup(inp): - # here Python signal handler will be invoked - # this book-keeping is to drain the pipe - wakeupsn.setEnabled(False) - rfd = wakeupsn.socket() - try: - os.read(int(rfd), 4096) - except OSError as inst: - print('failed to read wakeup fd: %s\n' % inst) - - wakeupsn.setEnabled(True) - - wakeupsn.activated.connect(handleWakeup) - - else: - # On Windows, non-blocking anonymous pipe or socket is - # not available. - - def null(): - ... - - # we need to 'kick' the python interpreter so it sees - # system signals - # https://stackoverflow.com/a/4939113/380231 - kick_timer = QtCore.QTimer() - kick_timer.timeout.connect(null) - kick_timer.start(50) - - cleanup = kick_timer.stop - - # we also need to make sure that the qApp never sees - # exceptions raised by python inside of a c++ callback (as - # it will segfault itself because due to the way the - # code is called there is no clear way to propagate that - # back to the python code. - vals = (None, None, None) - - old_sys_handler = sys.excepthook - - def my_exception_hook(exctype, value, traceback): - nonlocal vals - vals = (exctype, value, traceback) - event_loop.exit() - old_sys_handler(exctype, value, traceback) - - # this kill the Qt event loop when the plan is finished - killer_timer = QtCore.QTimer() - killer_timer.setSingleShot(True) - killer_timer.timeout.connect(start_killer_thread) - killer_timer.start(0) - - try: - sys.excepthook = my_exception_hook - event_loop.exec_() - # make sure any pending signals are processed - event_loop.processEvents() - if vals[1] is not None: - raise vals[1] - finally: - try: - cleanup() - finally: - sys.excepthook = old_sys_handler - elif 'ipympl' in backend or 'nbagg' in backend: - Gcf = matplotlib._pylab_helpers.Gcf - while True: - done = blocking_event.wait(.1) - for f_mgr in Gcf.get_all_fig_managers(): - if f_mgr.canvas.figure.stale: - f_mgr.canvas.draw() - if done: - return - else: - # We are not using matplotlib + Qt. Just wait on the Event. - blocking_event.wait()
- - -def _rearrange_into_parallel_dicts(readings): - data = {} - timestamps = {} - for key, payload in readings.items(): - data[key] = payload['value'] - timestamps[key] = payload['timestamp'] - return data, timestamps - - -def is_movable(obj): - """Check if object satisfies bluesky 'movable' interface. - - Parameters - ---------- - obj : Object - Object to test. - - Returns - ------- - boolean - True if movable, False otherwise. - """ - EXPECTED_ATTRS = ( - 'name', - 'parent', - 'read', - 'describe', - 'read_configuration', - 'describe_configuration', - 'set', - ) - return all(hasattr(obj, attr) for attr in EXPECTED_ATTRS) - - -class Movable(metaclass=abc.ABCMeta): - """ - Abstract base class for objects that satisfy the bluesky 'movable' interface. - - Examples - -------- - - .. code-block:: python - - m = hw.motor - # We need to detect if 'm' is a motor - if isinstance(m, Movable): - print(f"The object {m.name} is a motor") - """ - @classmethod - def __subclasshook__(cls, C): - # If the following condition is True, the object C is recognized - # to have Movable interface (e.g. a motor) - msg = """The Movable abstract base class is deprecated and will be removed in a future - version of bluesky. Please use bluesky.utils.is_movable(obj) to test if an object - satisfies the movable interface.""" - warnings.warn(msg, DeprecationWarning) - EXPECTED_ATTRS = ( - 'name', - 'parent', - 'read', - 'describe', - 'read_configuration', - 'describe_configuration', - 'set', - 'stop', - ) - return all(hasattr(C, attr) for attr in EXPECTED_ATTRS) -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_modules/index.html b/bluesky/_modules/index.html deleted file mode 100644 index 16bfe9f349..0000000000 --- a/bluesky/_modules/index.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - - Overview: module code — bluesky 1.6.7.post2+g888716e documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Overview: module code
  • - - -
  • - -
  • - -
- - -
-
- - - -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/api_changes.rst.txt b/bluesky/_sources/api_changes.rst.txt deleted file mode 100644 index f1aa7bf881..0000000000 --- a/bluesky/_sources/api_changes.rst.txt +++ /dev/null @@ -1,1425 +0,0 @@ -================= - Release History -================= - -v1.6.7 (2020-11-04) -=================== - -Fixed ------ - -* Tweak layout of plots produced by the Best-Effort Callback when showing - many LiveGrids. -* The :func:`bluesky.simulators.check_limits` simulator now calls - ``obj.check_value()`` instead of looking at ``obj.limits``. -* When a document is emitted from a RunEngine, a log message is always issued. - Previously, Resource and Datum documents were missed. -* Various docstrings were fixed to match the actual function signatures. -* The utility :func:`bluesky.utils.is_movable` for checking with an object - satifies the expected interfaced for a "movable" object now correctly treats - the ``stop`` method and ``position`` attribute as optional. -* Documentation about the expected interface for "movable" objects was - incomplete and has been revised to match reality. - -v1.6.6 (2020-08-26) -=================== - -Fixed ------ - -* :class:`bluesky.utils.PersistentDict` has new methods - :meth:`bluesky.utils.PersistentDict.reload` and - :meth:`bluesky.utils.PersistentDict.flush` to syncing from and to disk. It - flushes at garbage collection or system exit, which ensures that any values - that have been mutated are updated on disk. - -v1.6.5 (2020-08-06) -=================== - -Fixed ------ - -* LiveGrid and LiveScatter failed to update - -Enhancements ------------- - -* Expand the class of objects considered "moveable" to include those with expected - attributes defined as instance attributes - -v1.6.4 (2020-07-08) -=================== - -Fixed ------ - -* Allow ``:`` to be used in keynames and still format LiveTable. -* Address use of ``loop`` argument deprecated in Python 3.8. -* Ensure that ``bluesky.utils`` is importable from a background thread. (Do - not create an instance of `~bluesky.utils.DefaultDuringTask` at import time.) - -v1.6.3 (2020-06-25) -=================== - -Fixed ------ - -* Incorrect implementation of :func:`~bluesky.bundlers.RunBundler.collect` has been corrected. - -v1.6.2 (2020-06-05) -=================== - -Fixed ------ - -* Missing implementation details of :func:`~bluesky.bundlers.RunBundler.collect` have been added. - -v1.6.1 (2020-05-08) -=================== - -Added ------ - -* The plans :func:`~bluesky.plans.grid_scan` and - :func:`~bluesky.plans.rel_grid_scan` accept a new ``snake_axes`` parameter, - now matching what :func:`~bluesky.plans.list_grid_scan` and - :func:`~bluesky.plans.rel_list_grid_scan` do. This can be used to control - which axes follow a back-and-forth "snake-like" trajectory. - - .. code:: python - - # Default - snaking is disabled - grid_scan([hw.det], hw.motor, 1, 2, 5, hw.motor1, 7, 2, 10, hw.motor2, 3, 5, 4) - - # Snaking is explicitely disabled - grid_scan([hw.det], hw.motor, 1, 2, 5, hw.motor1, 7, 2, 10, hw.motor2, 3, 5, 4, snake_axes=False) - - # Snaking can also be disabled by providing empty list of motors - grid_scan([hw.det], hw.motor, 1, 2, 5, hw.motor1, 7, 2, 10, hw.motor2, 3, 5, 4, snake_axes=[]) - - # Snaking is enabled for all motors except the slowest hw.motor - grid_scan([hw.det], hw.motor, 1, 2, 5, hw.motor1, 7, 2, 10, hw.motor2, 3, 5, 4, snake_axes=True) - - # Snaking is enabled only for hw.motor1 - grid_scan([hw.det], hw.motor, 1, 2, 5, hw.motor1, 7, 2, 10, hw.motor2, 3, 5, 4, snake_axes=[hw.motor1]) - - # Snaking is enabled only for hw.motor1 and hw.motor2 - grid_scan([hw.det], hw.motor, 1, 2, 5, hw.motor1, 7, 2, 10, hw.motor2, 3, 5, 4, snake_axes=[hw.motor1, hw.motor2]) - - The old (harder to read) way of specifying "snake" parameters, interleaved - with the other parameters, is still supported for backward-compatibility. - - .. code:: python - - grid_scan([hw.det], hw.motor, 1, 2, 5, hw.motor1, 7, 2, 10, True, hw.motor2, 3, 5, 4, False) - - The two styles---interleaved parameters vs. the new ``snake_axes`` - parameter---cannot be mixed. Mixing them will cause a ``ValueError`` to be - raised. - -Fixed ------ - -* Fixed a regression in v1.6.0 which accidentally broke some usages of the - ``per_step`` parameter in scans. -* The plan :func:`bluesky.plans.fly` returned ``None`` by mistake. It now - returns the Run Start uid, as do all the other plans that module. - -v1.6.0 (2020-03-16) -=================== - -The most important change in this release is a complete reworking of how -bluesky interacts with the asyncio event loop. This resolves a long-running -issue of bluesky being incompatible with ``tornado >4``, which often tripped up -users in the context of using bluesky from Jupyter notebooks. - -There are several other new features and fixes, including new plans and more -helpful error messages, enumerated further below. - -Event loop re-factor --------------------- - -Previously, the :class:`~bluesky.run_engine.RunEngine` had been repeatedly starting and -stopping the asyncio event loop in :meth:`~bluesky.run_engine.RunEngine.__call__`, -:meth:`~bluesky.run_engine.RunEngine.request_pause`, :meth:`~bluesky.run_engine.RunEngine.stop`, in -:meth:`~bluesky.run_engine.RunEngine.abort`, :meth:`~bluesky.run_engine.RunEngine.halt`, and -:meth:`~bluesky.run_engine.RunEngine.resume`. This worked, but is bad practice. It -complicates attempts to integrate with the event loop with other tools. -Further, because as of tornado 5, tornado reports its self as an asyncio event -loop so attempts to start another asyncio event loop inside of a task fails -which means bluesky will not run in a jupyter notebook. To fix this we now -continuously run the event loop on a background thread and the -:class:`~bluesky.run_engine.RunEngine` object manages the interaction with creating tasks -on that event loop. To first order, users should not notice this change, -however details of how manage both blocking the user prompt and how we -suspend processing messages from a plan are radically different. -One consequence of running the event loop on a background thread is -that the code in plans and the callbacks is executed in that thread as well. -This means that plans and callbacks must now be threadsafe. - -API Changes -~~~~~~~~~~~ - -``install_qt_kicker`` deprecated -++++++++++++++++++++++++++++++++ - -Previously, we were running the asyncio event loop on the main thread -and blocked until it returned. This meant that if you were using -Matplotlib and Qt for plots they would effectively be "frozen" because -the Qt event loop was not being given a chance to run. We worked -around this by installing a 'kicker' task onto the asyncio event loop -that would periodically spin the Qt event loop to keep the figures -responsive (both to addition of new data from callbacks and from user -interaction). - -Now that we are running the event loop on a background thread this no -longer works because the Qt event loop must be run on the main thread. -Instead we use *during_task* to block the main thread by running the -Qt event loop directly. - - -``during_task`` kwarg to ``RunEngine.__init__`` -+++++++++++++++++++++++++++++++++++++++++++++++ - -We need to block the main thread in :meth:`~bluesky.run_engine.RunEngine.__call__` (and -:meth:`~bluesky.run_engine.RunEngine.resume`) until the user supplied plan is complete. -Previously, we would do this by calling ``self.loop.run_forever()`` to -start the asyncio event loop. We would then stop the event loop an -the bottom of ``RunEngine._run`` and in -:meth:`~bluesky.run_engine.RunEngine.request_pause` to un-block the main thread and return -control to the user terminal. Now we must find an alternative way to achieve -this effect. - -There is a a :class:`threading.Event` on the :class:`~bluesky.run_engine.RunEngine` that -will be set when the task for ``RunEngine._run`` in completed, -however we can not simple wait on that event as that would again cause the Qt -windows to freeze. We also do not want to bake a Matplotlib / Qt dependency -directly into the :class:`~bluesky.run_engine.RunEngine` so we added a hook, set at init -time, for an object expected to implement the method ``block(event)``. -While the RunEngine executes a plan, it is passed the :class:`threading.Event` -and is responsible for blocking until the Event is set. This function can do -other things (such as run the Qt event loop) during that time. The required -signature is :: - - def block(ev: Threading.Event) -> None: - "Returns when ev is set" - - -The default hook will handle the case of the Matplotilb Qt backend and -the case of Matplotlib not being imported. - - -``'wait_for'`` Msg now expects callables rather than futures -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -Messages are stashed and re-run when plans are interrupted which would -result in re-using the coroutines passed through. This has always -been broken, but due to the way were stopping the event loop to pause -the scan it was passing tests. - -Instead of directly passing the values passed into :func:`asyncio.wait`, we -now expect that the iterable passed in is callables with the signature:: - - def fut_fac() -> awaitable: - 'This must work multiple times' - -The persistent dict used by ``RE.md`` must be thread-safe -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -By default, ``RE.md`` is an ordinary dictionary, but any dict-like object may -be used. It is often convenient for the contents of that dictionary to persist -between sessions. To achieve this, we formerly recommended using -``~historydict.HistoryDict``. Unfortunately, -``~historydict.HistoryDict`` is not threadsafe and is not compatible with -bluesky's new concurrency model. We now recommend using -:class:`~bluesky.utils.PersistentDict`. See :ref:`md_persistence` for -instructions on how to migrate existing metadata. - -Callbacks must be thread-safe -+++++++++++++++++++++++++++++ - -Because callbacks now run on the background thread they must be -thread-safe. The place where this is most likely to come up is in the -context of plotting which generally creates a GUI window. Almost all -GUI frameworks insist that they only be interacted with only on the -main thread. In the case of Qt we provide -:class:`~bluesky.callbacks.mpl_plotting.QtAwareCallback` to manage -moving Qt work back to the main thread (via a Qt ``Signal``). - - -Plans must be thread-safe -+++++++++++++++++++++++++ - -Because the plans now execute on the background thread they must be -thread-safe if the touch any external state. Similarly the callbacks, -we expect that the most likely place for this to fail is with -plotting. In most cases this can be addressed by using a thread-safe -version of the callback. - - -Features --------- - -* Added support for :doc:`multi_run_plans`. -* Added better logging and convenience functions for managing it more easily. - See :doc:`debugging`. -* Generalized :func:`~bluesky.plans.list_scan` to work on any number of motors, - not just one. In v1.2.0, :func:`~bluesky.plans.scan` was generalized in the - same way. -* Added :func:`~bluesky.plans.list_grid_scan`. -* Added :func:`~bluesky.plan_stubs.rd`. -* Added :class:`~bluesky.suspenders.SuspendWhenChanged`. -* Added :func:`~bluesky.callbacks.core.make_callback_safe` and - :func:`~bluesky.callbacks.core.make_class_safe`. -* Added a ``per_shot`` parameter to :func:`bluesky.plans.count`, analogous to - the ``per_step`` parameter supported by plans that do scans. -* Accept ``**kwargs`` to :func:`~bluesky.plan_stubs.mv` and - :func:`~bluesky.plan_stubs.mvr`. Pass them through to all motors involved in - the move. Notably, this allows plans to pass a ``timeout`` parameter through - the ``obj.set()``. -* Added a new built-in RunEngine command, ``RE_class``, which sends the type of - the ``RunEngine`` into the generator. This allows the plan to know if it is - being consumed by the usual ``RunEngine``, a subclass, or some - non-responsive consumer like ``list``. -* Raise a more helpful error message if the ``num`` parameter given to - :func:`~bluesky.plans.scan` is not a whole number, as can happen if ``num`` is - mistaken to mean "step size". -* Report the version of bluesky and (if available) ophyd in the metadata. -* Add a more helpful error message if the value returned from some call to - ``obj.read()`` returns ``None`` instead of the expected dict. -* If the user tries to start a :class:`~bluesky.callbacks.zmq.RemoteDispatcher` - after it has been stopped, raise a more helpful error message. - -Bug Fixes ---------- - -* The ``state`` attribute of the ``RunEngine`` is now a read-only property, as - it should have always been. -* In the Best-Effort Callback, do not assume that the RunStart document - includes ``'scan_id'``, which is an optional key. -* The commandline utility ``bluesky-0MQ-proxy`` now works on Windows. -* The IPython integrations have been updated for compatibility with IPython 7. -* Added support for "adaptive fly scans" by enabling the ``'collect'`` message - to (optionally) return the Events it emitted. -* Fixed bug in tqdm-based progress bar where tqdm could be handed a value it - considered invalid. - -Other API Changes ------------------ - -* Removed attribute ``nnls`` from - :class:`bluesky.callbacks.best_effort.PeakResults`. It has always been - ``None`` (never implemented) and only served to cause confusion. - -v1.5.7 (2020-05-01) -=================== - -Bug Fixes ---------- - -This release fixes a bug that resulted in no configuration data related -to fly scans being added to descriptors. - - -v1.5.6 (2020-03-11) -=================== - -Added support for Python 3.8 and the following for forward-compatibility with -1.6.0. - -* :class:`bluesky.utils.PersistentDict` -* :class:`bluesky.callbacks.mpl_plotting.QtAwareCallback` - -See -`the 1.5.6 GH milestone `_ -for the complete list of changes. - -v1.5.5 (2019-08-16) -=================== - -Support fix ``bluesky.utils.register_transform`` with IPython >= 7 - - -v1.5.4 (2019-08-09) -=================== - -Support Maplotlib 3.1 and above. (Do not use deprecated and removed aspect -adjustable values.) - -v1.5.3 (2019-05-27) -=================== - -This release removes the dependency on an old version of the ``jsonschema`` -library and requires the latest version of the ``event-model`` library. - - -v1.5.2 (2019-03-11) -=================== - -This release fixes compatibility with matplotlib 2.x; at least some matplotlib -2.x releases are not compatible with the matplotlib plotting callbacks in -bluesky v1.5.1. This release of bluesky is compatible with all 2.x and 3.x -releases. - -v1.5.1 (2019-03-08) -=================== - -This release contains bug fixes and documentation updates. - -Features --------- - -* Use the ISO8601 delimiters for date in RE scans. - -Bug Fixes ---------- - -* Pin jsonschema <3 due to its deprecations. -* Stop using deprecated API in Matplotlib. - - -v1.5.0 (2019-01-03) -=================== - -This release includes many documentation fixes and handful of new features, -especially around improved logging. - -Features --------- - -* Logging has been increased and improved. -* A default handler is added to the ``'bluesky'`` logger at import time. A new - convenience function, :func:`~bluesky.set_handler`, addresses common cases - such as directing the log output to a file. -* The ``bluesky-0MQ-proxy`` script now supports a ``-v, --verbose`` option, - which logs every start and stop document received and a ``-vvv`` ("very - verbose") option, which logs every document of every type. -* The prefix on messages sent by :class:`bluesky.callbacks.zmq.Publisher` can - be set to arbitrary bytes. (In previous versions, the prefix was hardcoded to - an encoded combination of the hostname, process ID, and the Python object ID - of a RunEngine instance.) -* The RunEngine includes a human-readable, not-necessarily-unique ``scan_id`` - key in the RunStart document. The source of the ``scan_id`` is now pluggable - via a new parameter, ``scan_id_source``. See :doc:`run_engine_api` for - details. -* The convenience function, :func:`bluesky.utils.ts_msg_hook` accepts new - parameter ``file`` for directing the output to a file instead of the standard - out. -* It is possible to use those callbacks that do not require matplotlib without - importing it. - -Bug Fixes ---------- - -* Fixed BestEffortCallback's handling of integer data in plots. -* Fixed invalid escape sequence that produced a warning in Python 3.6. - -Breaking Changes ----------------- - -* The signature of :class:`bluesky.callbacks.zmq.RemoteDispatcher` has been - changed in a non-backward-compatible way. The parameters for filtering - messages by ``hostname``, ``pid``, and ``run_engine_id`` have been replaced - by one new parameter, ``prefix``. -* The default value of ``RunEngine.verbose`` is now ``True``, meaning that the - ``RunEngine.log`` is *not* disabled by default. - -Deprecations ------------- - -* The :class:`bluesky.callbacks.zmq.Publisher` accepts an optional RunEngine - instance, which the Publisher subscribes to automatically. This parameter has - been deprecated; users are now encouraged to subscribe the publisher to the - RunEngine manually, in the normal way (``RE.subscribe(publisher)``). The - parameter may be removed in a future release of bluesky. - -v1.4.1 (2018-09-24) -=================== - -This release fixes a single regression introduced in v1.4.0. We recommend all -users upgrade. - -Bug Fixes ---------- - -* Fix a critical typo that made - :class:`~bluesky.callbacks.mpl_plotting.LiveGrid` unusable. - -Note that the 1.4.x series is not compatible with newer versions of matplotlib; -it needs a version lower than 3.1.0 due to an API change in matplotlib. The -1.5.x series is compatible with matplotlib versions before and after the -change. - -v1.4.0 (2018-09-05) -=================== - -Features --------- - -* Added ability to control 'sense' of - :class:`~bluesky.callbacks.mpl_plotting.LiveGrid` (ex "positive goes - down and to the right") to match the coordinates in the hutch. -* Learned how to specify the serializer / deserializer for the zmq - publisher / client. -* Promoted the inner function from :func:`~bluesky.plan_stubs.one_nd_step` - to a top-level plan :func:`bluesky.plan_stubs.move_per_step`. -* Added flag to :func:`~bluesky.plans.ramp_plan` to control if a - data point is taken before the ramp starts. - -Bug Fixes ---------- - -* Ensure order stability in :func:`~bluesky.magics.get_labeled_devices` - on all supported versions of Python. -* Fixed typos, dev requirements, and build details. - - -v1.3.3 (2018-06-06) -=================== - -Bug Fixes ---------- - -* Fixed show-shopping RunEngine bug in flyer asset collection. (The impact of - this bug is expected to be low, as there *are* no flyers with asset - collection yet and the bug was discovered while writing the first one.) -* Fixed packaging issue where certain important files (notably - ``requirements.txt``) were not included in the source tarball. -* Made BestEffortCallback swallow errors related to matplotlib's "tight layout" - if the occur --- better to show a messy plot than error out. - -v1.3.2 (2018-05-24) -=================== - -Bug Fixes ---------- - -* Revised behavior of magics that integrate with ophyd's experimental - "labels" feature. The most important difference is that the ``%wa`` magic now - traverses the children of labeled devices to find any sub-devices that are - positioners. - -v1.3.1 (2018-05-19) -=================== - -Bug Fixes ---------- - -* Fixed race condition where monitored signals could emit an Event document - before the corresponding Event Descriptor document. -* Addressed incompatibilities with upcoming release of Python, 3.7. - -v1.3.0 (2018-05-15) -=================== - -Features --------- - -* When used with ophyd v1.2.0 or later, emit Resource and Datum documents - through the RunEngine. Previously, ophyd would insert these documents - directly into a database. This left other consumers with only partial - information (for example, missing file paths to externally-stored data) and - no guarantees around synchronization. Now, ophyd need not interact with a - database directly. All information flows through the RunEngine and out to any - subscribed consumers in a deterministic order. -* New Msg commands, ``install_suspender`` and ``remove_suspender``, allow plans - to temporarily add and remove Suspenders. -* The RunEngine's signal handling (i.e. Ctrl+C capturing) is now configurable. - The RunEngine accepts a list of ``context_managers`` that it will enter and - exit before and after running. By default, it has one context manager that - handles Ctrl+C. To disable Ctrl+C handling, pass in an empty list instead. - This can also be used to inject other custom behavior. -* Add new plans: :func:`~bluesky.plans.x2x_scan`, - :func:`~bluesky.plans.spiral_square_plan`, and - :func:`~bluesky.plans.rel_spiral_square_plan`. -* Add convenience methods for reviewing the available commands, - :meth:`~bluesky.run_engine.RunEngine.commands` and - :meth:`~bluesky.run_engine.RunEngine.print_command_registry`. -* Add a ``crossings`` attribute to ``PeakStats``. - -Bug Fixes ---------- - -* When resuming after a suspender, call ``resume()`` on all devices (if - present). -* Fixed BEC LiveGrid plot for a motor with one step. -* A codepath in ``LiveFit`` that should have produced a warning produced an - error instead. - -Breaking Changes ----------------- - -* User-defined callbacks subscribed to the RunEngine ``'all'`` stream must - accept documents with names ``'resource'``, ``'datum'`` and ``'bulk_datum'``. - It does not necessarily have to heed their contents, but it must not fall - over if it receives one. - -Deprecations ------------- - -* The IPython "magics", always marked as experimental, have been reworked. - Instead of relying on the singleton lists, ``BlueskyMagics.positioners`` and - ``BlueskyMagics.detectors``, the magics now scrape the user namespace for - objects that implement the ``_ophyd_labels_`` interface. See :doc:`magics` - for the new usage. The magics will revert to their old behavior if the - singleton lists are non-empty, but they will produce a warning. The old - behavior will be removed in a future release. - -v1.2.0 (2018-02-20) -=================== - -Features --------- - -* Refreshed documentation with a new :doc:`tutorial` section. -* Extend :func:`.scan` and :func:`.rel_scan` to - handle multiple motors, rendering :func:`.inner_product_scan` and - :func:`relative_inner_product_scan` redundant. -* A new plan stub, :func:`~bluesky.plan_stubs.repeat`, repeats another plan N - times with optional interleaved delays --- a kind of customizable version of - :func:`~bluesky.plans.count`. -* Better validation of user-defined ``per_step`` functions and more informative - error messages to match. - -Bug Fixes ---------- - -* Fix axes orientation in :class:`.LiveRaster`. -* Make :class:`.BestEffortCallback` display multi-motor scans properly. -* Fix bug in :func:`.ts_msg_hook` where it conflated month and minute. Also, - include sub-second precision. -* Avoid situation where plan without hints caused the - :class:`.BestEffortCallback` to error instead of do its best to guess useful - behavior. -* Skip un-filled externally-stored data in :class:`.LiveTable`. This fixes a - bug where it is expecting array data but gets UUID (``datum_id``) and errors - out. - -Deprecations ------------- - -* The :func:`~bluesky.plan_stubs.caching_repeater` plan has been deprecated - because it is incompatible with some preprocessors. It will be removed in - a future release of bluesky. It was not documented in any previous releases - and rarely if ever used, so the impact of this removal is expected to be low. - -v1.1.0 (2017-12-19) -=================== - -This release fixes small bugs in v1.0.0 and introduces one new feature. The -API changes or deprecations are not expected to affect many users. - -Features --------- - -* Add a new command to the :class:`~bluesky.run_engine.RunEngine`, ``'drop'``, - which jettisons the currently active event bundle without saving. This is - useful for workflows that generate many readings that can immediately be - categorized as not useful by the plan and summarily discarded. -* Add :func:`~bluesky.utils.install_kicker`, which dispatches automatically to - :func:`~bluesky.utils.install_qt_kicker` or - :func:`~bluesky.utils.install_nb_kicker` depending on the current matplotlib - backend. - -Bug Fixes ---------- - -* Fix the hint for :func:`~bluesky.plans.inner_product_scan`, which previously - used a default hint that was incorrect. - -Breaking Changes and Deprecations ---------------------------------- - -* In :func:`~bluesky.plans.tune_centroid`, change the meaning of the - ``step_factor`` parameter to be the factor to reduce the range of each - successive iteration. Enforce bounds on the motion, and determine the - centroid from each pass separately. -* The :class:`~bluesky.preprocessors.SupplementalData` preprocessor inserts its - instructions in a more logical order: first baseline readings, then - monitors, then flyers. Previously, the order was reversed. -* The suspender :class:`~bluesky.suspenders.SuspendInBand` has been renamed to - :class:`~bluesky.suspenders.SuspendWhenOutsideBand` to make its meaning more - clear. Its behavior has not changed: it suspends when a value exits a given - range. The original, confusing name now issues a warning. -* The suspender :class:`~bluesky.suspenders.SuspendOutBand`, which - counter-intuitively suspends *when a value enters a given range*, has been - deprecated. (If some application is found for this unusual scenario, the user - can always implement a custom suspender to handle it.) - -v1.0.0 (2017-11-07) -=================== - -This tag marks an important release for bluesky, signifying the conclusion of -the early development phase. From this point on, we intend that this project -will be co-developed between multiple facilities. The 1.x series is planned to -be a long-term-support release. - -Bug Fixes ---------- - -* :func:`~bluesky.plan_stubs.mv` and :func:`~bluesky.plan_stubs.mvr` now works - on pseudopositioners. -* :func:`~bluesky.preprocessors.reset_positions_wrapper` now works on - pseudopositioners. -* Plans given an empty detectors list, such as ``count([])``, no longer break - the :class:`~bluesky.callbacks.best_effort.BestEffortCallback`. - -v0.11.0 (2017-11-01) -==================== - -This is the last release before 1.0.0. It contains major restructurings and -general clean-up. - -Breaking Changes and Deprecations ---------------------------------- - -* The :mod:`bluesky.plans` module has been split into - - * :mod:`bluesky.plans` --- plans that create a run, such as :func:`count` - and :func:`scan` - * :mod:`bluesky.preprocessors` --- plans that take in other plans and - motify them, such as :func:`baseline_wrapper` - * :mod:`bluesky.plan_stubs` --- small plans meant as convenient building - blocks for creating custom plans, such as :func:`trigger_and_read` - * :mod:`bluesky.object_plans` and :mod:`bluesky.cntx`, containing - legacy APIs to plans that were deprecated in a previous release and - will be removed in a future release. - -* The RunEngine raises a ``RunEngineInterrupted`` exception when interrupted - (e.g. paused). The optional argument ``raise_if_interrupted`` has been - removed. -* The module :mod:`bluesky.callbacks.scientific` has been removed. -* ``PeakStats`` has been moved to :mod:`bluesky.callbacks.fitting`, and - :func:`plot_peak_stats` has been moved to `bluesky.callbacks.mpl_plotting`. -* The synthetic 'hardware' objects in ``bluesky.examples`` have been relocated - to ophyd (bluesky's sister package) and aggressively refactored to be more - closely aligned with the behavior of real hardware. The ``Reader`` and - ``Mover`` classes have been removed in favor of ``SynSignal``, - ``SynPeriodicSignal``, ``SynAxis``, ``SynSignalWithRegistry``. - -Features --------- - -* Add :func:`stub_wrapper` and :func:`stub_decorator` that strips - open_run/close_run and stage/unstage messages out of a plan, so that it can - be reused as part of a larger plan that manages the scope of a run manually. -* Add :func:`tune_centroid` plan that iteratively finds the centroid of a - single peak. -* Allow devices with couple axes to be used in N-dimensional scan plans. -* Add :func:`contingency_wrapper` and :func:`contingency_decorator` for - richer cleanup specification. -* The number of events in each event stream is recorded in the RunStop document - under the key 'num_events'. -* Make the message shown when the RunEngine is paused configurable via the - attribute ``RunEngine.pause_msg``. - -Bug Fixes ---------- - -* Fix ordering of dimensions in :func:`grid_scan` hints. -* Show Figures created internally. -* Support a negative direction for adaptive scans. -* Validate that all descriptors with a given (event stream) name have - consistent data keys. -* Correctly mark ``exit_status`` field in RunStop metadata based on which - termination method was called (abort, stop, halt). -* ``LiveFitPlot`` handles updates more carefully. - -Internal Changes ----------------- - -* The :mod:`bluesky.callbacks` package has been split up into more modules. - Shim imports maintain backward compatibility, except where noted in the - section on API Changes above. -* Matplotlib is now an optional dependency. If it is not importable, - plotting-related callbacks will not be available. -* An internal change to the RunEngine supports ophyd's new Status object API - for adding callbacks. - -v0.10.3 (2017-09-12) -==================== - -Bug Fixes ---------- - -* Fix critical :func:`baseline_wrapper` bug. -* Make :func:`plan_mutator` more flexible. (See docstring.) - -v0.10.2 (2017-09-11) -==================== - -This is a small release with bug fixes and UI improvements. - -Bug Fixes ---------- - -* Fix bug wherein BestEffortCallback tried to plot strings as floats. The - intended behavior is to skip them and warn. - -Features --------- - -* Include a more informative header in BestEffortCallback. -* Include an 'Offset' column in %wa output. - -v0.10.1 (2017-09-11) -==================== - -This release is equivalent to v0.10.2. The number was skipped due to packaging -problems. - -v0.10.0 (2017-09-06) -==================== - -Highlights ----------- - -* Automatic best-effort visualization and peak-fitting is available for all - plans, including user-defined ones. -* The "SPEC-like" API has been fully removed, and its most useful features have - been applied to the library in a self-consistent way. See the next section - for detailed instructions on migrating. -* Improved tooling for streaming documents over a network for live processing - and visualization in a different process or on a different machine. - -Breaking Changes ----------------- - -* The modules implementing what was loosely dubbed a "SPEC-like" interface - (``bluesky.spec_api`` and ``bluesky.global_state``) have been entirely - removed. This approach was insufficently similar to SPEC to satisfy SPEC - users and confusingly inconsistent with the rest of bluesky. - - The new approach retains the good things about that interface and makes them - available for use with *all* plans consistently, including user defined ones. - Users who have been fully utilitzing these "SPEC-like" plans will notice four - differences. - - 1. No ``gs.DETS``. Just use your own variable for detectors. Instead of: - - .. code-block:: python - - # OLD ALTERNATIVE, NO LONGER SUPPORTED - - from bluesky.global_state import gs - from bluesky.spec_api import ct - - gs.DETS = # a list of some detectors - RE(ct()) - - do: - - .. code-block:: python - - from bluesky.plans import count - - dets = # a list of some detectors - RE(count(dets)) - - Notice that you can use multiple lists to enable easy task switching. - Instead of continually updating one global list like this: - - .. code-block:: python - - # OLD ALTERNATIVE, NO LONGER SUPPORTED - - gs.DETS = # some list of detectors - RE(ct()) - - gs.DETS.remove(some_detector) - gs.DETS.append(some_other_detector) - RE(ct()) - - you can define as many lists as you want and call them whatever you want. - - .. code-block:: python - - d1 = # a list of some detectors - d2 = # a list of different detectors - RE(count(d1)) - RE(count(d2)) - - 2. Automatic baseline readings, concurrent monitoring, and "flying" - can be set up uniformly for all plans. - - Formerly, a list of devices to read at the beginning and the end of each - run ("baseline" readings), a list of signals to concurrent monitor, and - a list of "flyers" to run concurrently were configured like so: - - .. code-block:: python - - # OLD ALTERNATIVE, NO LONGER SUPPORTED - - from bluesky.spec_api import ct - - gs.BASELINE_DEVICES = # a list of devices to read at start and end - gs.MONTIORS = # a list of signals to monitor concurrently - gs.FLYERS = # a list of "flyable" devices - - gs.DETS = # a list of detectors - - RE(ct()) # monitoring, flying, and baseline readings are added - - And formerly, those settings only affected the behavior of the "SPEC-like" - plans, such as ``ct`` and ``ascan``. They were ignored by their - counterparts ``count`` and ``scan``, as well as user-defined plans. This - was not desirable! - - This scheme has been replaced by the - :ref:`supplemental data `, which can be - used to globally modify *all* plans, including user-defined ones. - - .. code-block:: python - - from bluesky.plans import count - - # one-time configuration - from bluesky import SupplementalData - sd = SupplementalData() - RE.preprocessors.append(sd) - - # interactive use - sd.monitors = # a list of signals to monitor concurrently - sd.flyers = # a list of "flyable" devices - sd.baseline = # a list of devices to read at start and end - - dets = # a list of detectors - RE(count(dets)) # monitoring, flying, and baseline readings are added - - 3. Automatic live visualization and peak analysis can be set up uniformly for - all plans. - - Formerly, the "SPEC-like" plans such as ``ct`` and ``ascan`` automatically - set up a suitable table and a plot, while their "standard" vanilla - counterparts, :func:`bluesky.plans.count` and :func:`bluesky.plans.scan` - required explicit, detailed instructions to do so. Now, a best-effort - table and plot can be made for *all* plans, including user-defined ones, - by invoking this simple configuration: - - .. code-block:: python - - from bluesky.plans import count - - # one-time configuration - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - RE.subscribe(bec) - - # interactive use - dets = # a list of detectors - RE(count(dets), num=5)) # automatically prints table, shows plot - - Use ``bec.disable()`` and ``bec.enable()`` to temporarily toggle the - output off and on. - - 4. Peak anallysis, now computed automatically by the BestEffortCallback - above, can be viewed with a keyboard shortcut. The peak statistics, - formerly encapsulated in ``gs.PS``, are now organized differently. - - For each plot, simple peak-fitting is performed in the background. Of - course, it may or may not be applicable depending on your data, and it is - not shown by default. To view fitting annotations in a plot, click the - plot area and press Shift+P. (Lowercase p is a shortcut for - "panning" the plot.) - - To access the peak-fit statistics programmatically, use ``bec.peaks``. For - convenience, you may alias this like: - - .. code-block:: python - - peaks = bec.peaks - - Inside ``peaks``, access various statistics like: - - .. code-block:: python - - peaks.com - peaks.cen - peaks.max - peaks.min - - Each of these is a dictionary with an entry for each field that was fit. - For example, the 'center of mass' peak statistics for a field named - ``'ccd_stats1_total'`` would be accessed like - ``peaks.com['ccd_stats1_total']``. -* The functions and classes in the module ``bluesky.callbacks.broker`` require - a instance of ``Broker`` to be passed in as an argument. They used to default - to the 'singleton' instance via ``from databroker import db``, which is now a - deprecated usage in databroker. -* The plan preprocessors ``configure_count_time_wrapper`` and - ``configure_count_time_decorator`` were moved to ``bluesky.plans`` from - ``bluesky.spec_api``, reverting a change made in v0.9.0. -* The 0MQ pubsub integration classes ``Publisher`` and ``RemoteDispatcher`` - have been overhauled. They have been moved from - :mod:`bluesky.callbacks.zmqpub` and :mod:`bluesky.callbacks.zmqsub` to - :mod:`bluesky.callbacks.zmq` and their signatures have been changed to match - similar utilities in the pydata ecosystem. See the Enhancements section for - more information. -* The module ``bluesky.qt_kicker`` has been removed. Its former contents are - avaiable in ``bluesky.utils``. The module was originally deprecated in April - 2016, and it has been issuing warnings about this change since. -* The plan ``bluesky.plans.input`` has been renamed - ``bluesky.plans.input_plan`` to avoid shadowing a builtin if the module is - bulk-imported. The plan was previously undocumented and rarely used, so the - impact of this change on users is expected to be small. - -Deprecations ------------- - -* The module :mod:`bluesky.plan_tools` has been renamed - :mod:`bluesky.simualtors`. In the new module, - :func:`bluesky.plan_tools.print_summary`` has been renamed - :func:`bluesky.simulators.summarize_plan`. - The old names are supported in this release, with a warning, but will be - removed in a future release. -* The Object-Orientated plans (``Count``, ``Scan``, etc.) have been deprecated - and will be removed in a future release. Their documentation has been - removed. -* The plan context managers (``run_context``, ``stage_context``, etc.) have - been deprecated and will be removed in a future release. They were never - documented or widely used. -* The method :meth:`bluesky.Dispatcher.subscribe` (which is encapsulated into - :class:`bluesky.run_engine.RunEngine` and inherited by - :class:`bluesky.callbacks.zmq.RemoteDispatcher`) has a new signature. The - former signature was ``subscribe(name, func)``. The new signature is - ``subscribe(func, name='all')``. Because the meaning of the arguments is - unambigious (they must be a callable and a string, respectively) the old - order will be supported indefeinitely, with a warning. - -Features --------- - -* A :doc:`progress bar ` add-on is available. -* As addressed above: - * The new :ref:`supplemental data ` feature make it - easy to set up "baseline" readings and asynchronous acquisition in a way - that applies automatically to all plans. - * The new :ref:`best-effort callback ` sets up - automatic terminal output and plots for all plans, including user-defined - ones. -* ``LivePlot`` now accepts ``x='time'``. It can set t=0 to the UNIX epoch or to - the start of the run. It also accepts ``x='seq_num'``---a synonym for - ``x=None``, which remains the default. -* A new simulator :func:`bluesky.simulators.check_limits` verifies that a plan - will not try to move a movable device outside of its limits. -* A new plan, :func:`bluesky.plan.mvr`, has been added as a relative counterpart - to :func:`bluesky.plan.mv`. -* The 0MQ pubsub integration classes :class:`bluesky.callbacks.zmq.Publisher`` - and :class:`bluesky.callbacks.zmq.RemoteDispatcher` have been simplified. - A new class :class:`bluesky.callbacks.zmq.Proxy` and command-line utility - ``bluesky-0MQ-proxy`` has been added to streamline configuration. -* Metadata recorded by many built-in plans now includes a new item, - ``'hints'``, which is used by the best-effort callback to produce useful - visualizations. Additionally, the built-in examples devices have - :ref:`a new hints attribute `. Its content may change or expand in - future releases as this new feature is explored. -* Some :doc:`IPython magics ` mimicing the SPEC API have been added. - These are experimental and may be altered or removed in the future. - -Bug Fixes ---------- - -* Using the "fake sleep" feature of simulated Movers (motors) caused them to - break. -* The ``requirements.txt`` failed to declare that bluesky requires matplotlib. - -v0.9.0 (2017-05-08) -=================== - -Breaking Changes ----------------- - -* Moved ``configure_count_time_wrapper`` and - ``configure_count_time_decorator`` to ``bluesky.spec_api`` from - ``bluesky.plans``. -* The metadata reported by step scans that used to be labeled ``num_steps`` - is now renamed ``num_points``, generally considered a less ambiguous name. - Separately, ``num_interals`` (which one might mistakenly assume is what was - meant by ``num_steps``) is also stored. - - -v0.8.0 (2017-01-03) -=================== - -Features --------- - -* If some plan or callback has hung the RunEngine and blocked its normal - ability to respond to Ctrl+C by pausing, it is not possible to trigger a - "halt" (emergency stop) by hammering Ctrl+C more than ten times. - -Bug Fixes ---------- - -* Fix bug where failed or canceled movements could cause future executions of - the RunEngine to error. -* Fix bug in ``plan_mutator`` so that it properly handles return values. One - effect of this fix is that ``baseline_wrapper`` properly passed run uids - through. -* Fix bug in ``LiveFit`` that broke multivariate fits. -* Minor fixes to example detectors. - -Breaking Changes ----------------- - -* A ``KeyboardInterrupt`` exception captured during a run used to cause the - RunEngine to pause. Now it halts instead. - -v0.7.0 (2016-11-01) -=================== - -Features --------- - -* Nonlinear least-squares minimization callback ``LiveFit`` with - ``LiveFitPlot`` -* Added ``RunEngine.clear_suspenders()`` convenience method. -* New ``RunEngine.preprocessors`` list that modifies all plans passed to the - RunEngine. -* Added ``RunEngine.state_hook`` to monitor state changes, akin to ``msg_hook``. -* Added ``pause_for_debug`` options to ``finalize_wrapper`` which allows pauses - the RunEngine before performing any cleanup, making it easier to debug. -* Added many more examples and make it easier to create simulated devices that - generate interesting simulated data. They have an interface closer to the - real devices implemented in ophyd. -* Added ``mv``, a convenient plan for moving multiple devices in parallel. -* Added optional ``RunEngine.max_depth`` to raise an error if the RunEngine - thinks it is being called from inside a function. - -Bug Fixes ---------- - -* The 'monitor' functionality was completely broken, packing configuration - into the wrong structure and starting seq_num from 0 instead of 1, which is - the (regrettable) standard we have settled on. -* The RunEngine coroutines no longer mutate the messages they receive. -* Fix race condition in ``post_run`` callback. -* Fix bugs in several callbacks that caused them not to work on saved documents - from the databroker. Also, make them call ``super()`` to play better with - multiple inheritance in user code. - - -Breaking Changes ----------------- - -* The flag ``RunEngine.ignore_callback_exceptions`` now defaults to False. -* The plan ``complete``, related to fly scans, previously had ``wait=True`` by - default, although its documentation indicated that ``False`` was the default. - The code has been changed to match the documentation. Any calls to - ``complete`` that are expected to be blocking should be updated with the - keyword ``wait=True``. -* Completely change the API of ``Reader`` and ``Mover``, the classes for - definding simulated devices. -* The bluesky interface now expects the ``stop`` method on a device to accept - an optional ``success`` argument. -* The optional, undocumented ``fig`` argument to ``LivePlot`` has been - deprecated and will be removed in a future release. An ``ax`` argument has - been added. Additionally, the axes used by ``LiveGrid`` and ``LiveScatter`` is - configurable through a new, optional ``ax`` argument. -* The "shortcut" where mashing Ctrl+C three times quickly ran ``RE.abort()`` - has been removed. -* Change the default stream name for monitors to ``_monitor`` from - ``signal_name>-monitor`` (underscore vs. dash). The impact of this change is - minimal because, as noted above, the monitor functionality was completely - broken in previous releases. - -v0.6.4 (2016-09-07) -=================== - -Features --------- - -* Much-expanded and overhauled documentation. -* Add ``aspect`` argument to ``LiveGrid``. -* Add ``install_nb_kicker`` to get live-updating matplotlib figures in the - notebook while the RunEngine is running. -* Simulated hardware devices ``Reader`` and ``Mover`` can be easily customized - to mock a wider range of behaviors, for testing and demos. -* Integrate the SPEC API with mew global state attribute ``gs.MONITORS``. -* Callbacks that use the databroker accept an optional ``Broker`` instance - as an argument. - -Bug Fixes ---------- - -* Minor fix in the tilt computation for spiral scans. -* Expost 'tilt' option through SPEC-like API -* The "infinite count" (``ct`` with ``num=None``) should spawn a LivePlot. -* ``finalize_decorator`` accepts a callable (e.g., generator function) - and does not accept an iterable (e.g., generator instance) -* Restore ``gs.FLYERS`` integration to the SPEC API (accidentally removed). - -Breaking Changes ----------------- - -* The API for the simulated hardware example devices ``Reader`` and ``Mover`` - has been changed to make them more general. -* Remove ``register_mds`` metadatastore integration. - -v0.6.3 (2016-08-16) -=================== - -Features --------- - -* Change how "subscription factories" are handled, making them configurable - through global state. -* Make PeakStats configurable through global state. -* Add an experimental utility for passing documents over a network and - processing them on a separate process or host, using 0MQ. -* Add ``monitor_during_wrapper`` and corresponding decorator. -* Add ``stage_wrapper`` and corresponding decorator. -* Built-in plans return the run uid that they generated. -* Add a new ``ramp_plan`` for taking data while polling the status of a - movement. - -Bug Fixes ---------- - -* Boost performance by removing unneeded "sleep" step in message processing. -* Fix bug related to rewinding in preparation for resuming. - -Breaking Changes ----------------- - -* Remove the ``planify`` decorator and the plan context managers. These were - experimental and ultimately proved problematic because they make it difficult - to pass through return values cleanly. -* Remove "lossy" subscriptions feature, rendered unnecessary by the utility for - processing documents in separate processes (see Enhancements, above). - -v0.6.2 (2016-07-26) -=================== - -Bug Fixes ---------- - -* Make ``make_decorator`` return proper decorators. The original implementation - returned functions that could not actually be used as decorators. - -v0.6.1 (2016-07-25) -=================== - -This release contained only a minor UX fix involving more informative error -reporting related to Area Detector plugin port configuration. - -v0.6.0 (2016-07-25) -=================== - -Features --------- - -* Address the situation where plan "rewinding" after a pause or suspension - interacted badly with some devices. There are now three ways to temporarily - turn off rewinding: a Msg with a new 'rewindable' command; a special - attribute on the device that the ``trigger_and_read`` plan looks for; - and a special exception that devices can raise when their ``pause`` method - is called. All three of these features should be considered experimental. - They will likely be consolidated in the future once their usage is tested - in the wild. -* Add new plan wrappers and decorators: ``inject_md_wrapper``, ``run_wrapper``, - ``rewindable_wrapper``. - -Bug Fixes ---------- - -* Fix bug where RunEngine was put in the "running" state, encountered an - error before starting the ``_run`` coroutine, and thus never switch back to - "idle." -* Ensure that plans are closed correctly and that, if they fail to close - themselves, a warning is printed. -* Allow plan to run its cleanup messages (``finalize``) when the RunEngine is - stopped or aborted. -* When an exception is raised, give each plan in the plan stack an opportunity - to handle it. If it is handled, carry on. -* The SPEC-style ``tw`` was not passing its parameters through to the - underlying ``tweak`` plan. -* Silenced un-needed suspenders warnings -* Fix bug in separating devices - -Internal Changes ----------------- - -* Reduce unneeded usage of ``bluesky.plans.single_gen``. -* Don't emit create/save messages with no reads in between. -* Re-work exception handling in main run engine event loop. - -v0.5.3 (2016-06-06) -=================== - -Breaking Changes ----------------- - -* ``LiveTable`` only displays data from one event stream. -* Remove used global state attribute ``gs.COUNT_TIME``. - -Bug Fixes ---------- - -* Fix "infinite count", ``ct(num=None)``. -* Allow the same data keys to be present in different event streams. But, as - before, a given data key can only appear once per event. -* Make SPEC-style plan ``ct`` implement baseline readings, referring to - ``gs.BASELINE_DETS``. -* Upon resuming after a deferred pause, clear the deferred pause request. -* Make ``bluesky.utils.register_transform`` character configurable. - -v0.5.2 (2016-05-25) -=================== - -Features --------- - -* Plans were reimplemented as simple Python generators instead of custom Python - classes. The old "object-oriented" plans are maintained for - back-compatibility. See plans documentation to review new capabilities. - -Breaking Changes ----------------- - -* SPEC-style plans are now proper generators, not bound to the RunEngine. - -v0.5.0 (2016-05-11) -=================== - -Breaking Changes ----------------- - -* Move ``bluesky.scientific_callbacks`` to ``bluesky.callbacks.scientific`` - and ``bluesky.broker_callbacks`` to ``bluesky.callbacks.broker``. -* Remove ``bluesky.register_mds`` whose usage can be replaced by: - ``import metadatastore.commands; RE.subscribe_lossless('all', metadatastore.commands.insert)`` -* In all occurrences, the argument ``block_group`` has been renamed ``group`` - for consistency. This affects the 'trigger' and 'set' messages. -* The (not widely used) ``Center`` plan has been removed. It may be - distributed separately in the future. -* Calling a "SPEC-like" plan now returns a generator that must be passed - to the RunEngine; it does not execute the plan with the global RunEngine in - gs.RE. There is a convenience wrapper available to restore the old behavior - as desired. But since that usage renders the plans un-composable, it is - discouraged. -* The 'time' argument of the SPEC-like plans is a keyword-only argument. -* The following special-case SPEC-like scans have been removed - - * hscan - * kscan - * lscan - * tscan - * dtscan - * hklscan - * hklmesh - - They can be defined in configuration files as desired, and in that location - they will be easier to customize. -* The ``describe`` method on flyers, which returns an iterable of dicts of - data keys for one or more descriptors documents, has been renamed to - ``describe_collect`` to avoid confusion with ``describe`` on other devices, - which returns a dict of data keys for one descriptor document. -* An obscure feature in ``RunEngine.request_pause`` has been removed, which - involved removing the optional arguments ``callback`` and ``name``. - -v0.4.3 (2016-03-03) -=================== - -Bug Fixes ---------- - -* Address serious performance problem in ``LiveTable``. - -v0.4.2 (2016-03-02) -=================== - -Breaking Changes ----------------- - -* Stage the ultimate parent ("root") when a device is staging its child, making - it impossible to leave a device in a partially-staged state. - -v0.4.1 (2016-02-29) -=================== - -Features --------- - -* Give every event stream a ``name``, using ``'primary'`` by default. -* Record a mapping of device/signal names to ordered data keys in the - EventDescriptor. -* Let ``LiveRaster`` account for "snaked" trajectories. - -Bug Fixes ---------- - -* ``PeakStats.com`` is a scalar, not a single-element array. -* Restore Python 3.4 compatibility. - -v0.4.0 (2016-02-23) -=================== - -(TO DO) - -v0.3.2 (2015-10-28) -=================== - -(TO DO) - -v0.3.1 (2015-10-15) -=================== - -(TO DO) - -v0.3.0 (2015-10-14) -=================== - -Breaking Changes ----------------- - -* Removed ``RunEngine.persistent_fields``; all fields in ``RE.md`` persist - between runs by default. -* No metadata fields are "reserved"; any can be overwritten by the user. -* No metadata fields are absolutely required. The metadata validation function - is user-customizable. The default validation function behaves the same - as previous versions of bluesky, but it is no longer manditory. -* The signature of ``RunEngine`` has changed. The ``logbook`` argument is now - keyword-only, and there is a new keyword-only argument, ``md_validator``. - See docstring for details. -* The ``configure`` method on readable objects now takes a single optional - argument, a dictionary that the object can use to configure itself however - it sees fit. The ``configure`` method always has a new return value, a tuple - of dicts describing its old and new states: - ``old, new = obj.configure(state)`` -* Removed method ``increment_scan_id`` -* `callbacks.broker.post_run` API and docstring brought into agreement. - The API is change to expect a callable with signature - ``foo(doc_name, doc)`` rather than - - - a callable which takes a document (as documented) - - an object with ``start``, ``descriptor``, ``event`` and ``stop`` - methods (as implemented). - - If classes derived from ``CallbackBase`` are being used this will not - not have any effect on user code. - -v0.2.3 (2015-09-29) -=================== - -(TO DO) - -v0.2.2 (2015-09-24) -=================== - -(TO DO) - -v0.2.1 (2015-09-24) -=================== - -(TO DO) - -v0.2.0 (2015-09-22) -=================== - -(TO DO) - -v0.1.0 (2015-06-25) -=================== - -Initial release diff --git a/bluesky/_sources/api_changes.txt b/bluesky/_sources/api_changes.txt deleted file mode 100644 index 426e971d7d..0000000000 --- a/bluesky/_sources/api_changes.txt +++ /dev/null @@ -1,263 +0,0 @@ -Release Notes -============= - -v0.7.0 ------- - -Enhancements -^^^^^^^^^^^^ - -* Nonlinear least-squares minimzation callback ``LiveFit`` with ``LiveFitPlot`` -* Added ``RunEngine.clear_suspenders()`` convenience method. -* New ``RunEngine.preprocessors`` list that modifies all plans passed to the - RunEngine. -* Added ``RunEngine.state_hook`` to monitor state changes, akin to ``msg_hook``. -* Added ``pause_for_debug`` options to ``finalize_wrapper`` which allows pauses - the RunEngine before performing any cleanup, making it easier to debug. -* Added many more examples and make it easier to create simulated devices that - generate interesting simulated data. They have an interface closer to the - real devices implemented in ophyd. -* Added ``mv``, a convenient plan for moving multiple devices in parallel. -* Added optional ``RunEngine.max_depth`` to raise an error if the RunEngine - thinks it is being called from inside a function. - -Bug Fixes -^^^^^^^^^ - -* The 'monitor' functionality was completely broken, packing configuration - into the wrong structure and starting seq_num from 0 instead of 1, which is - the (regrettable) standard we have settled on. -* The RunEngine coroutines no longer mutate the messages they receive. -* Fix race condition in ``post_run`` callback. -* Fix bugs in several callbacks that caused them not to work on saved documents - from the databroker. Also, make them call ``super()`` to play better with - multiple inheritance in user code. - - -API Changes -^^^^^^^^^^^ - -* The flag ``RunEngine.ignore_callback_exceptions`` now defaults to False. -* The plan ``complete``, related to fly scans, previously had ``wait=True`` by - default, although its documentation indicated that ``False`` was the default. - The code has been changed to match the documentation. Any calls to - ``complete`` that are expected to be blocking should be updated with the - keyword ``wait=True``. -* Completely change the API of ``Reader`` and ``Mover``, the classes for - definding simulated devices. -* The bluesky interface now expects the ``stop`` method on a device to accept - an optional ``success`` argument. -* The optional, undocumented ``fig`` argument to ``LivePlot`` has been - deprecated and will be removed in a future release. An ``ax`` argument has - been added. Additionally, the axes used by ``LiveRaster`` and ``LiveMesh`` is - configurable through a new, optional ``ax`` argument. -* The "shortcut" where mashing Ctrl+C three times quickly ran ``RE.abort()`` - has been removed. -* Change the default stream name for monitors to ``_monitor`` from - ``signal_name>-monitor`` (underscore vs. dash). The impact of this change is - minimal because, as noted above, the monitor functionality was completely - broken in previous releases. - -v0.6.4 ------- - -Enhancements -^^^^^^^^^^^^ - -* Much-expanded and overhauled documentation. -* Add ``aspect`` argument to ``LiveRaster``. -* Add ``install_nb_kicker`` to get live-updating matplotlib figures in the - notebook while the RunEngine is running. -* Simulated hardware devices ``Reader`` and ``Mover`` can be easily customized - to mock a wider range of behaviors, for testing and demos. -* Integrate the SPEC API with mew global state attribute ``gs.MONITORS``. - -Bug Fixes -^^^^^^^^^ - -* Minor fix in the tilt computation for spiral scans. -* Expost 'tilt' option through SPEC-like API -* The "infinite count" (``ct`` with ``num=None``) should spawn a LivePlot. -* ``finalize_decorator`` accepts a callable (e.g., generator function) - and does not accept an iterable (e.g., generator instance) -* Restore ``gs.FLYERS`` integration to the SPEC API (accidentally removed). - -API Changes -^^^^^^^^^^^ - -* The API for the simulated hardware example devices ``Reader`` and ``Mover`` - has been changed to make them more general. -* Remove ``register_mds`` metadatastore integration. -* Callbacks that use the databroker accept an optional ``Broker`` instance - as an argument. - -v0.6.3 ------- - -Enhancements -^^^^^^^^^^^^ -* Change how "subscription factories" are handled, making them configurable - through global state. -* Make PeakStats configurable through global state. -* Add an experimental utility for passing documents over a network and - processing them on a separate process or host, using 0MQ. -* Add ``monitor_during_wrapper`` and corresponding decorator. -* Add ``stage_wrapper`` and corresponding decorator. -* Built-in plans return the run uid that they generated. -* Add a new ``ramp_plan`` for taking data while polling the status of a - movement. - -Bug Fixes -^^^^^^^^^ -* Boost performance by removing unneeded "sleep" step in message processing. -* Fix bug related to rewinding in preparation for resuming. - -API Changes -^^^^^^^^^^^ -* Remove the ``planify`` decorator and the plan context managers. These were - experimental and ultimately proved problematic because they make it difficult - to pass through return values cleanly. -* Remove "lossy" subscriptions feature, rendered unnecessary by the utility for - processing documents in separate processes (see Enhancements, above). - -v0.6.2 ------- - -Bug Fixes -^^^^^^^^^ -* Make ``make_decorator`` return proper decorators. The original implementation - returned functions that could not actually be used as decorators. - -v0.6.1 ------- - -This release contained only a minor UX fix involving more informative error -reporting. - -v0.6.0 ------- - -Enhancements -^^^^^^^^^^^^ -* Address the situation where plan "rewinding" after a pause or suspension - interacted badly with some devices. There are now three ways to temporarily - turn off rewinding: a Msg with a new 'rewindable' command; a special - attribute on the device that the ``trigger_and_read`` plan looks for; - and a special exception that devices can raise when their ``pause`` method - is called. All three of these features should be considered experimental. - They will likely be consolidated in the future once their usage is tested - in the wild. -* Add new plan wrappers and decorators: ``inject_md_wrapper``, ``run_wrapper``, - ``rewindable_wrapper``. - -Bug Fixes -^^^^^^^^^ -* Fix bug where RUnEngine was put in the "running" state, encountered an - error before starting the ``_run`` coroutine, and thus never switch back to - "idle." -* Ensure that plans are closed correctly and that, if they fail to close - themselves, a warning is printed. -* Allow plan to run its cleanup messages (``finalize``) when the RunEngine is - stopped or aborted. -* When an exception is raised, give each plan in the plan stack an opportunity - to handle it. If it is handled, carry on. -* The SPEC-style ``tw`` was not passing its parameters through to the - underlying ``tweak`` plan. -* Silenced un-needed suspenders warnings -* Fix bug in separating devices - -Cleanup -^^^^^^^ -* Reduce unneeded usage of ``bluesky.plans.single_gen``. -* Don't emit create/save messages with no reads in between. -* Re-work exception handling in main run engine event loop. - -v0.5.3 ------- - -API Changes -^^^^^^^^^^^ -* ``LiveTable`` only displays data from one event stream. -* Remove used global state attribute ``gs.COUNT_TIME``. - -Bug Fixes -^^^^^^^^^ -* Fix "infinite count", ``ct(num=None)``. -* Allow the same data keys to be present in different event streams. But, as - before, a given data key can only appear once per event. -* Make SPEC-style plan ``ct`` implement baseline readings, referring to - ``gs.BASELINE_DETS``. -* Upon resuming after a deferred pause, clear the deferred pause request. -* Make ``bluesky.utils.register_transform`` character configurable. - -v0.5.2 ------- -* Plans were completely refactored. The API of the exist plans is supported - for back-compatibility. See plans documentation to review new capabilities. -* SPEC-style plans are now proper generators, not bound to the RunEngine. - - -v0.5.0 ------- - -* Move ``bluesky.scientific_callbacks`` to ``bluesky.callbacks.scientific`` - and ``bluesky.broker_callbacks`` to ``bluesky.callbacks.broker``. -* Remove ``bluesky.register_mds`` whose usage can be replaced by: - ``import metadatastore.commands; RE.subscribe_lossless('all', metadatastore.commands.insert)`` -* In all occurrences, the argument ``block_group`` has been renamed ``group`` - for consistency. This affects the 'trigger' and 'set' messages. -* The (not widely used) ``Center`` plan has been removed. It may be - distributed separately in the future. -* Calling a "SPEC-like" plan now returns a generator that must be passed - to the RunEngine; it does not execute the plan with the global RunEngine in - gs.RE. There is a convenience wrapper available to restore the old behavior - as desired. But since that usage renders the plans un-composable, it is - discouraged. -* The 'time' argument of the SPEC-like plans is a keyword-only argument. -* The following special-case SPEC-like scans have been removed - - * hscan - * kscan - * lscan - * tscan - * dtscan - * hklscan - * hklmesh - - They can be defined in configuration files as desired, and in that location - they will be easier to customize. -* The ``describe`` method on flyers, which returns an iterable of dicts of - data keys for one or more descriptors documents, has been renamed to - ``describe_collect`` to avoid confusion with ``describe`` on other devices, - which returns a dict of data keys for one descriptor document. -* An obscure feature in ``RunEngine.request_pause`` has been removed, which - involved removing the optional arguments ``callback`` and ``name``. - -v0.3.0 ------- - -* Removed ``RunEngine.persistent_fields``; all fields in ``RE.md`` persist - between runs by default. -* No metadata fields are "reserved"; any can be overwritten by the user. -* No metadata fields are absolutely required. The metadata validation function - is user-customizable. The default validation function behaves the same - as previous versions of bluesky, but it is no longer manditory. -* The signature of ``RunEngine`` has changed. The ``logbook`` argument is now - keyword-only, and there is a new keyword-only argument, ``md_validator``. - See docstring for details. -* The ``configure`` method on readable objects now takes a single optional - argument, a dictionary that the object can use to configure itself however - it sees fit. The ``configure`` method always has a new return value, a tuple - of dicts describing its old and new states: - ``old, new = obj.configure(state)`` -* Removed method ``increment_scan_id`` -* `callbacks.broker.post_run` API and docstring brought into agreement. - The API is change to expect a callable with signature - ``foo(doc_name, doc)`` rather than - - - a callable which takes a document (as documented) - - an object with ``start``, ``descriptor``, ``event`` and ``stop`` - methods (as implemented). - - If classes derived from `CallbackBase` are being used this will not - not have any effect on user code. diff --git a/bluesky/_sources/appendix.rst.txt b/bluesky/_sources/appendix.rst.txt deleted file mode 100644 index 5e3573a8de..0000000000 --- a/bluesky/_sources/appendix.rst.txt +++ /dev/null @@ -1,99 +0,0 @@ -Appendix -======== - -This section covers Python language features that may be new to some readers. -They are used by bluesky but not *unique* Wherever possible, we to bluesky. - -.. _yield_from_primer: - -A Primer on ``yield`` and ``yield from`` ----------------------------------------- - -This is a very brief primer on the Python syntax ``yield`` and ``yield from``, -a feature of the core language that we will use extensively. - -A Python *function* returns once: - -.. ipython:: python - - def f(): - return 1 - - f() - -A Python *generator* is like a function with multiple exit points. Calling a -generator produces an *iterator* that yields one value at a time. After -each ``yield`` statement, its execution is suspended. - -.. ipython:: python - - def f(): - yield 1 - yield 2 - -We can exhaust the generator (i.e., get all its values) by calling ``list()``. - -.. ipython:: python - - list(f()) - -We can get one value at a time by calling ``next()`` - -.. ipython:: python - - it = f() - next(it) - next(it) - -or by looping through the values. - -.. ipython:: python - - for val in f(): - print(val) - -To examine what is happening when, we can add prints. - -.. ipython:: python - - def verbose_f(): - print("before 1") - yield 1 - print("before 2") - yield 2 - -.. ipython:: python - - it = verbose_f() - next(it) - next(it) - -Notice that execution is suspended after the first yield statement. The -second ``print`` is not run until we resume execution by requesting a second -value. This is a useful feature of generators: they can express "lazy" -execution. - -Generators can delegate to other generators using ``yield from``. This is -syntax we commonly use to combine plans. - -.. ipython:: python - - def double_f(): - yield from f() - yield from f() - -The above is equivalent to: - -.. ipython:: python - - def double_f(): - for val in f(): - yield val - for val in f(): - yield val - -The ``yield from`` syntax is just more succinct. - -.. ipython:: python - - list(double_f()) diff --git a/bluesky/_sources/async.rst.txt b/bluesky/_sources/async.rst.txt deleted file mode 100644 index 47911bb12f..0000000000 --- a/bluesky/_sources/async.rst.txt +++ /dev/null @@ -1,139 +0,0 @@ -.. currentmodule:: bluesky.plans - -Asynchronous Acquisition -======================== - -This section encompasses "fly scans," "monitoring," and in general handling -data acquisition that is occurring at different rates. - -.. note:: - - If you are here because you just want to "move two motors at once" or - something in that category, you're in luck: you don't need anything as - complex as what we present in this section. Read about multidimensional - plans in the section on :doc:`plans`. - -In short, "flying" is for acquisition at high rates and "monitoring" is for -acquisition at an irregular or slow rate. Monitoring does not guarantee that -all readings will be captured; i.e. monitoring is lossy. It is susceptible to -network glitches. But flying, by contract, is not lossy if correctly -implementated. - -**Flying** means: "Let the hardware take control, cache data externally, and -then transfer all the data to the RunEngine at the end." This is essential when -the data acquisition rates are faster than the RunEngine or Python can go. - -.. note:: - - As a point of reference, the RunEngine processes message at a rate of - about 35k/s (not including any time added by whatever the message *does*). - - - .. code-block:: python - - In [3]: %timeit RE(Msg('null') for j in range(1000)) - 10 loops, best of 3: 26.8 ms per loop - -**Monitoring** a means acquiring readings whenever a new reading is available, -at a device's natural update rate. For example, we might monitor background -condition (e.g., beam current) on the side while executing the primary logic of -a plan. The documents are generated in real time --- not all at the end, like -flying --- so if the update rate is too high, monitoring can slow down the -execution of the plan. As mentioned above, monitoring is also lossy: if network -traffic is high, some readings may be missed. - -Flying ------- - -In bluesky's view, there are three steps to "flying" a device during a scan. - -1. **Kickoff**: Begin accumulating data. A 'kickoff' command completes once - acquisition has successfully started. -2. **Complete**: This step tells the device, "I am ready whenever you are - ready." If the device is just collecting until it is told to stop, it will - report that it is ready immediately. If the device is executing some - predetermined trajectory, it will finish before reporting ready. -3. **Collect**: Finally, the data accumulated by the device is transferred to - the RunEngine and processed like any other data. - -To "fly" one or more "flyable" devices during a plan, bluesky provides a -`preprocessor `. It is available as a wrapper, -:func:`fly_during_wrapper` - -.. code-block:: python - - from ophyd.sim import det, flyer1, flyer2 # simulated hardware - from bluesky.plans import count - from bluesky.preprocessors import fly_during_wrapper - - RE(fly_during_wrapper(count([det], num=5), [flyer1, flyer2])) - -and as a decorator, :func:`fly_during_decorator`. - -.. code-block:: python - - from ophyd.sim import det, flyer1, flyer2 # simulated hardware - from bluesky.plans import count - from bluesky.preprocessors import fly_during_wrapper - - # Define a new plan for future use. - fly_and_count = fly_during_decorator([flyer1, flyer2])(count) - - RE(fly_and_count([det])) - -Alternatively, if you are using :ref:`supplemental_data`, simply -append to or extend its list of flyers to kick off during every run: - -.. code-block:: python - - from ophyd.sim import flyer1, flyer2 - - # Assume sd is an instance of the SupplementalData set up as - # descripted in the documentation linked above. - sd.flyers.extend([flyer1, flyer2]) - -They will be included with all plans until removed. - -.. _async_monitoring: - -Monitoring ----------- - -To monitor some device during a plan, bluesky provides a -`preprocessor `. It -is available as a wrapper, :func:`monitor_during_wrapper` - -.. code-block:: python - - from ophyd.sim import det, det1 - from bluesky.plans import count - from bluesky.preprocessors import monitor_during_wrapper - - # Record any updates from det1 while 'counting' det 5 times. - RE(monitor_during_wrapper(count([det], num=5), [det1])) - -and as a decorator, :func:`monitor_during_decorator`. - -.. code-block:: python - - from ophyd.sim import det, det1 - from bluesky.plans import count - from bluesky.preprocessors import monitor_during_wrapper - - # Define a new plan for future use. - monitor_and_count = monitor_during_decorator([det1])(count) - - RE(monitor_and_count([det])) - -Alternatively, if you are using :ref:`supplemental_data`, simply -append to or extend its list of signals to monitor: - -.. code-block:: python - - from ophyd.sim import det1 - - # Assume sd is an instance of the SupplementalData set up as - # descripted in the documentation linked above. - sd.monitors.append(det1) - -They will be included with all plans until removed. diff --git a/bluesky/_sources/async.txt b/bluesky/_sources/async.txt deleted file mode 100644 index 09cb975456..0000000000 --- a/bluesky/_sources/async.txt +++ /dev/null @@ -1,127 +0,0 @@ -.. currentmodule:: bluesky.plans - -Asynchronous Acquisition -======================== - -This section encompasses "fly scans," "monitoring," and in general handling -data acquisition that is occurring at different rates. - -.. note:: - - If you are here because you just want to "move two motors at once" or - something in that category, you're in luck: you don't need anything as - complex as what we present in this section. Read about multidimensional - plans in the section on :doc:`plans`. - -In short, "flying" is for acquisition at high rates and "monitoring" is for -acquisition an irregular or slow rate. - -**Flying** means: "Let the hardware take control, cache data externally, and -then transfer all the data to the RunEngine at the end." This is essential when -the data acquisition rates are faster than the RunEngine or Python can go. - -.. note:: - - As a point of reference, the RunEngine processes message at a rate of - about 35k/s (not including any time added by whatever the message *does*). - - - .. code-block:: python - - In [3]: %timeit RE(Msg('null') for j in range(1000)) - 10 loops, best of 3: 26.8 ms per loop - -**Monitoring** a means acquiring readings whenever a new reading is available, -at a device's natural update rate. For example, we might monitor background -condition (e.g., beam current) on the side while executing the primary logic of -a plan. The documents are generated in real time --- not all at the end, like -flying --- so if the update rate is too high, monitoring can slow down the -execution of the plan. - -Flying ------- - -In bluesky's view, there are three steps to "flying" a device during a scan. - -1. **Kickoff**: Begin accumulating data. A 'kickoff' command completes once - acquisition has successfully started. -2. **Complete**: This step tells the device, "I am ready whenever you are - ready." If the device is just collecting until it is told to stop, it will - report that is it ready immediately. If the device is executing some - predetermined trajectory, it will finish before reporting ready. -3. **Collect**: Finally, the data accumulated by the device is transferred to - the RunEngine and processed like any other data. - -To "fly" one or more "flyable" devices during a plan, bluesky provides a -`preprocessor `. It is available as a wrapper, -:func:`fly_during_wrapper` - -.. code-block:: python - - from bluesky.examples import det, flyer1, flyer2 # simulated hardware - from bluesky.plans import count, fly_during_wrapper - - RE(fly_during_wrapper(count([det], num=5), [flyer1, flyer2])) - -and as a decorator, :func:`fly_during_decorator`. - -.. code-block:: python - - from bluesky.examples import det, flyer1, flyer2 # simulated hardware - from bluesky.plans import count, fly_during_decorator - - # Define a new plan for future use. - fly_and_count = fly_during_decorator([flyer1, flyer2])(count) - - RE(fly_and_count([det])) - -Alternatively, if you are using the `SPEC-like Plan API `, simply add -flyers to the global state: - -.. code-block:: python - - from bluesky.global_state import gs - from bluesky.examples import flyer1, flyer2 - - gs.FLYERS = [flyer1, flyer2] - -They will be included with all plans until removed. - -Monitoring ----------- - -To monitor some device during a plan, bluesky provides a -`preprocessor `. It -is available as a wrapper, :func:`monitor_during_wrapper` - -.. code-block:: python - - from bluesky.examples import det, det1 - from bluesky.plans import count, monitor_during_wrapper - - # Record any updates from det1 while 'counting' det 5 times. - RE(monitor_during_wrapper(count([det], num=5), [det1])) - -and as a decorator, :func:`monitor_during_decorator`. - -.. code-block:: python - - from bluesky.examples import det, det1 - from bluesky.plans import count, monitor_during_decorator - - # Define a new plan for future use. - monitor_and_count = monitor_during_decorator([det1])(count) - - RE(monitor_and_count([det])) - -Alternatively, if you are using the `SPEC-like Plan API `, simply add -devices to be monitored to the global state: - -.. code-block:: python - - from bluesky.global_state import gs - from bluesky.examples import det1 - - gs.MONITORS = [det1] - -They will be included with all plans until removed. diff --git a/bluesky/_sources/bluesky.plans.AdaptiveScan.txt b/bluesky/_sources/bluesky.plans.AdaptiveScan.txt deleted file mode 100644 index 8054b7b1e4..0000000000 --- a/bluesky/_sources/bluesky.plans.AdaptiveScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.AdaptiveScan -========================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: AdaptiveScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~AdaptiveScan.__init__ - ~AdaptiveScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.Count.txt b/bluesky/_sources/bluesky.plans.Count.txt deleted file mode 100644 index 31316c48ad..0000000000 --- a/bluesky/_sources/bluesky.plans.Count.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.Count -=================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: Count - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Count.__init__ - ~Count.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.InnerProductScan.txt b/bluesky/_sources/bluesky.plans.InnerProductScan.txt deleted file mode 100644 index 2de60c6fe3..0000000000 --- a/bluesky/_sources/bluesky.plans.InnerProductScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.InnerProductScan -============================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: InnerProductScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~InnerProductScan.__init__ - ~InnerProductScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.ListScan.txt b/bluesky/_sources/bluesky.plans.ListScan.txt deleted file mode 100644 index 072d61c909..0000000000 --- a/bluesky/_sources/bluesky.plans.ListScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.ListScan -====================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: ListScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~ListScan.__init__ - ~ListScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.LogScan.txt b/bluesky/_sources/bluesky.plans.LogScan.txt deleted file mode 100644 index 1bb09fc7a2..0000000000 --- a/bluesky/_sources/bluesky.plans.LogScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.LogScan -===================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: LogScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~LogScan.__init__ - ~LogScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.OuterProductScan.txt b/bluesky/_sources/bluesky.plans.OuterProductScan.txt deleted file mode 100644 index 46a5518411..0000000000 --- a/bluesky/_sources/bluesky.plans.OuterProductScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.OuterProductScan -============================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: OuterProductScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~OuterProductScan.__init__ - ~OuterProductScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeAdaptiveScan.txt b/bluesky/_sources/bluesky.plans.RelativeAdaptiveScan.txt deleted file mode 100644 index d24e4ebb81..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeAdaptiveScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeAdaptiveScan -================================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeAdaptiveScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeAdaptiveScan.__init__ - ~RelativeAdaptiveScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeInnerProductScan.txt b/bluesky/_sources/bluesky.plans.RelativeInnerProductScan.txt deleted file mode 100644 index 5217bdad57..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeInnerProductScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeInnerProductScan -====================================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeInnerProductScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeInnerProductScan.__init__ - ~RelativeInnerProductScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeListScan.txt b/bluesky/_sources/bluesky.plans.RelativeListScan.txt deleted file mode 100644 index b90fd2935e..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeListScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeListScan -============================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeListScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeListScan.__init__ - ~RelativeListScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeLogScan.txt b/bluesky/_sources/bluesky.plans.RelativeLogScan.txt deleted file mode 100644 index ea5171d466..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeLogScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeLogScan -============================= - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeLogScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeLogScan.__init__ - ~RelativeLogScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeOuterProductScan.txt b/bluesky/_sources/bluesky.plans.RelativeOuterProductScan.txt deleted file mode 100644 index 8324b82f40..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeOuterProductScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeOuterProductScan -====================================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeOuterProductScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeOuterProductScan.__init__ - ~RelativeOuterProductScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeScan.txt b/bluesky/_sources/bluesky.plans.RelativeScan.txt deleted file mode 100644 index 0f75533d06..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeScan -========================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeScan.__init__ - ~RelativeScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeSpiralFermatScan.txt b/bluesky/_sources/bluesky.plans.RelativeSpiralFermatScan.txt deleted file mode 100644 index cfefcaf69d..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeSpiralFermatScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeSpiralFermatScan -====================================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeSpiralFermatScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeSpiralFermatScan.__init__ - ~RelativeSpiralFermatScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.RelativeSpiralScan.txt b/bluesky/_sources/bluesky.plans.RelativeSpiralScan.txt deleted file mode 100644 index 6914ffbc59..0000000000 --- a/bluesky/_sources/bluesky.plans.RelativeSpiralScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.RelativeSpiralScan -================================ - -.. currentmodule:: bluesky.plans - -.. autoclass:: RelativeSpiralScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RelativeSpiralScan.__init__ - ~RelativeSpiralScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.Scan.txt b/bluesky/_sources/bluesky.plans.Scan.txt deleted file mode 100644 index ccb5643e24..0000000000 --- a/bluesky/_sources/bluesky.plans.Scan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.Scan -================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: Scan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Scan.__init__ - ~Scan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.ScanND.txt b/bluesky/_sources/bluesky.plans.ScanND.txt deleted file mode 100644 index 95de1f789e..0000000000 --- a/bluesky/_sources/bluesky.plans.ScanND.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.ScanND -==================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: ScanND - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~ScanND.__init__ - ~ScanND.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.SpiralFermatScan.txt b/bluesky/_sources/bluesky.plans.SpiralFermatScan.txt deleted file mode 100644 index bbb7aa7a72..0000000000 --- a/bluesky/_sources/bluesky.plans.SpiralFermatScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.SpiralFermatScan -============================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: SpiralFermatScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SpiralFermatScan.__init__ - ~SpiralFermatScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.SpiralScan.txt b/bluesky/_sources/bluesky.plans.SpiralScan.txt deleted file mode 100644 index 80cc59f331..0000000000 --- a/bluesky/_sources/bluesky.plans.SpiralScan.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.SpiralScan -======================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: SpiralScan - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SpiralScan.__init__ - ~SpiralScan.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.Tweak.txt b/bluesky/_sources/bluesky.plans.Tweak.txt deleted file mode 100644 index 3987323af4..0000000000 --- a/bluesky/_sources/bluesky.plans.Tweak.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.plans.Tweak -=================== - -.. currentmodule:: bluesky.plans - -.. autoclass:: Tweak - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Tweak.__init__ - ~Tweak.set - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.abs_set.txt b/bluesky/_sources/bluesky.plans.abs_set.txt deleted file mode 100644 index 00ee510180..0000000000 --- a/bluesky/_sources/bluesky.plans.abs_set.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.abs_set -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: abs_set \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.adaptive_scan.txt b/bluesky/_sources/bluesky.plans.adaptive_scan.txt deleted file mode 100644 index 2cc1752895..0000000000 --- a/bluesky/_sources/bluesky.plans.adaptive_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.adaptive_scan -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: adaptive_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.baseline_context.txt b/bluesky/_sources/bluesky.plans.baseline_context.txt deleted file mode 100644 index 8b7f533810..0000000000 --- a/bluesky/_sources/bluesky.plans.baseline_context.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.baseline_context -============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: baseline_context \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.baseline_decorator.txt b/bluesky/_sources/bluesky.plans.baseline_decorator.txt deleted file mode 100644 index d3b7e6a97e..0000000000 --- a/bluesky/_sources/bluesky.plans.baseline_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.baseline_decorator -================================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: baseline_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.baseline_wrapper.txt b/bluesky/_sources/bluesky.plans.baseline_wrapper.txt deleted file mode 100644 index 096e6c0448..0000000000 --- a/bluesky/_sources/bluesky.plans.baseline_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.baseline_wrapper -============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: baseline_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.broadcast_msg.txt b/bluesky/_sources/bluesky.plans.broadcast_msg.txt deleted file mode 100644 index 6e694f24fe..0000000000 --- a/bluesky/_sources/bluesky.plans.broadcast_msg.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.broadcast_msg -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: broadcast_msg \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.caching_repeater.txt b/bluesky/_sources/bluesky.plans.caching_repeater.txt deleted file mode 100644 index 883badb921..0000000000 --- a/bluesky/_sources/bluesky.plans.caching_repeater.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.caching_repeater -============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: caching_repeater \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.checkpoint.txt b/bluesky/_sources/bluesky.plans.checkpoint.txt deleted file mode 100644 index af4d4a8ea2..0000000000 --- a/bluesky/_sources/bluesky.plans.checkpoint.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.checkpoint -======================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: checkpoint \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.clear_checkpoint.txt b/bluesky/_sources/bluesky.plans.clear_checkpoint.txt deleted file mode 100644 index b83a99c4c8..0000000000 --- a/bluesky/_sources/bluesky.plans.clear_checkpoint.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.clear_checkpoint -============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: clear_checkpoint \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.close_run.txt b/bluesky/_sources/bluesky.plans.close_run.txt deleted file mode 100644 index 2bec636499..0000000000 --- a/bluesky/_sources/bluesky.plans.close_run.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.close_run -======================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: close_run \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.collect.txt b/bluesky/_sources/bluesky.plans.collect.txt deleted file mode 100644 index a0cf26e273..0000000000 --- a/bluesky/_sources/bluesky.plans.collect.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.collect -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: collect \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.complete.txt b/bluesky/_sources/bluesky.plans.complete.txt deleted file mode 100644 index 72f84aaf7e..0000000000 --- a/bluesky/_sources/bluesky.plans.complete.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.complete -====================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: complete \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.configure.txt b/bluesky/_sources/bluesky.plans.configure.txt deleted file mode 100644 index e2d23aed16..0000000000 --- a/bluesky/_sources/bluesky.plans.configure.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.configure -======================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: configure \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.count.txt b/bluesky/_sources/bluesky.plans.count.txt deleted file mode 100644 index 1c585fed2a..0000000000 --- a/bluesky/_sources/bluesky.plans.count.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.count -=================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: count \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.create.txt b/bluesky/_sources/bluesky.plans.create.txt deleted file mode 100644 index 3414908e81..0000000000 --- a/bluesky/_sources/bluesky.plans.create.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.create -==================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: create \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.deferred_pause.txt b/bluesky/_sources/bluesky.plans.deferred_pause.txt deleted file mode 100644 index a9d884e4b0..0000000000 --- a/bluesky/_sources/bluesky.plans.deferred_pause.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.deferred_pause -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: deferred_pause \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.event_context.txt b/bluesky/_sources/bluesky.plans.event_context.txt deleted file mode 100644 index b9cb270563..0000000000 --- a/bluesky/_sources/bluesky.plans.event_context.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.event_context -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: event_context \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.finalize_decorator.txt b/bluesky/_sources/bluesky.plans.finalize_decorator.txt deleted file mode 100644 index ab4d5d9cab..0000000000 --- a/bluesky/_sources/bluesky.plans.finalize_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.finalize_decorator -================================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: finalize_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.finalize_wrapper.txt b/bluesky/_sources/bluesky.plans.finalize_wrapper.txt deleted file mode 100644 index 71a6c671c3..0000000000 --- a/bluesky/_sources/bluesky.plans.finalize_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.finalize_wrapper -============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: finalize_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.fly.txt b/bluesky/_sources/bluesky.plans.fly.txt deleted file mode 100644 index 8c6d791104..0000000000 --- a/bluesky/_sources/bluesky.plans.fly.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.fly -================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: fly \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.fly_during_decorator.txt b/bluesky/_sources/bluesky.plans.fly_during_decorator.txt deleted file mode 100644 index c917c22fbd..0000000000 --- a/bluesky/_sources/bluesky.plans.fly_during_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.fly_during_decorator -================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: fly_during_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.fly_during_wrapper.txt b/bluesky/_sources/bluesky.plans.fly_during_wrapper.txt deleted file mode 100644 index 0b7e70eea9..0000000000 --- a/bluesky/_sources/bluesky.plans.fly_during_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.fly_during_wrapper -================================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: fly_during_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.inject_md_decorator.txt b/bluesky/_sources/bluesky.plans.inject_md_decorator.txt deleted file mode 100644 index 065de3be43..0000000000 --- a/bluesky/_sources/bluesky.plans.inject_md_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.inject_md_decorator -================================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: inject_md_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.inject_md_wrapper.txt b/bluesky/_sources/bluesky.plans.inject_md_wrapper.txt deleted file mode 100644 index 15cf326770..0000000000 --- a/bluesky/_sources/bluesky.plans.inject_md_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.inject_md_wrapper -=============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: inject_md_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.inner_product_scan.txt b/bluesky/_sources/bluesky.plans.inner_product_scan.txt deleted file mode 100644 index b5b447a0b9..0000000000 --- a/bluesky/_sources/bluesky.plans.inner_product_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.inner_product_scan -================================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: inner_product_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.kickoff.txt b/bluesky/_sources/bluesky.plans.kickoff.txt deleted file mode 100644 index eaff356587..0000000000 --- a/bluesky/_sources/bluesky.plans.kickoff.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.kickoff -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: kickoff \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.lazily_stage_decorator.txt b/bluesky/_sources/bluesky.plans.lazily_stage_decorator.txt deleted file mode 100644 index 2f443509a0..0000000000 --- a/bluesky/_sources/bluesky.plans.lazily_stage_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.lazily_stage_decorator -==================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: lazily_stage_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.lazily_stage_wrapper.txt b/bluesky/_sources/bluesky.plans.lazily_stage_wrapper.txt deleted file mode 100644 index e6e3b991c9..0000000000 --- a/bluesky/_sources/bluesky.plans.lazily_stage_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.lazily_stage_wrapper -================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: lazily_stage_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.list_scan.txt b/bluesky/_sources/bluesky.plans.list_scan.txt deleted file mode 100644 index d3dd04f9fb..0000000000 --- a/bluesky/_sources/bluesky.plans.list_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.list_scan -======================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: list_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.log_scan.txt b/bluesky/_sources/bluesky.plans.log_scan.txt deleted file mode 100644 index 6d16a3d67d..0000000000 --- a/bluesky/_sources/bluesky.plans.log_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.log_scan -====================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: log_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.make_decorator.txt b/bluesky/_sources/bluesky.plans.make_decorator.txt deleted file mode 100644 index 7e65bab287..0000000000 --- a/bluesky/_sources/bluesky.plans.make_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.make_decorator -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: make_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.monitor.txt b/bluesky/_sources/bluesky.plans.monitor.txt deleted file mode 100644 index 0a65b38837..0000000000 --- a/bluesky/_sources/bluesky.plans.monitor.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.monitor -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: monitor \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.monitor_context.txt b/bluesky/_sources/bluesky.plans.monitor_context.txt deleted file mode 100644 index 8670a04158..0000000000 --- a/bluesky/_sources/bluesky.plans.monitor_context.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.monitor_context -============================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: monitor_context \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.monitor_during_decorator.txt b/bluesky/_sources/bluesky.plans.monitor_during_decorator.txt deleted file mode 100644 index 0b3ab9ad4c..0000000000 --- a/bluesky/_sources/bluesky.plans.monitor_during_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.monitor_during_decorator -====================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: monitor_during_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.monitor_during_wrapper.txt b/bluesky/_sources/bluesky.plans.monitor_during_wrapper.txt deleted file mode 100644 index 985ec5bef5..0000000000 --- a/bluesky/_sources/bluesky.plans.monitor_during_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.monitor_during_wrapper -==================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: monitor_during_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.msg_mutator.txt b/bluesky/_sources/bluesky.plans.msg_mutator.txt deleted file mode 100644 index 34fe7b577a..0000000000 --- a/bluesky/_sources/bluesky.plans.msg_mutator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.msg_mutator -========================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: msg_mutator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.mv.txt b/bluesky/_sources/bluesky.plans.mv.txt deleted file mode 100644 index d5c0752af0..0000000000 --- a/bluesky/_sources/bluesky.plans.mv.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.mv -================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: mv \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.null.txt b/bluesky/_sources/bluesky.plans.null.txt deleted file mode 100644 index 9e785bea54..0000000000 --- a/bluesky/_sources/bluesky.plans.null.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.null -================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: null \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.one_1d_step.txt b/bluesky/_sources/bluesky.plans.one_1d_step.txt deleted file mode 100644 index 497e48d3ef..0000000000 --- a/bluesky/_sources/bluesky.plans.one_1d_step.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.one_1d_step -========================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: one_1d_step \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.one_nd_step.txt b/bluesky/_sources/bluesky.plans.one_nd_step.txt deleted file mode 100644 index 00069b0a6f..0000000000 --- a/bluesky/_sources/bluesky.plans.one_nd_step.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.one_nd_step -========================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: one_nd_step \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.open_run.txt b/bluesky/_sources/bluesky.plans.open_run.txt deleted file mode 100644 index f38c4a5fd7..0000000000 --- a/bluesky/_sources/bluesky.plans.open_run.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.open_run -====================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: open_run \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.outer_product_scan.txt b/bluesky/_sources/bluesky.plans.outer_product_scan.txt deleted file mode 100644 index 6cb20d56eb..0000000000 --- a/bluesky/_sources/bluesky.plans.outer_product_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.outer_product_scan -================================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: outer_product_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.pause.txt b/bluesky/_sources/bluesky.plans.pause.txt deleted file mode 100644 index cc5ce73e63..0000000000 --- a/bluesky/_sources/bluesky.plans.pause.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.pause -=================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: pause \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.pchain.txt b/bluesky/_sources/bluesky.plans.pchain.txt deleted file mode 100644 index 6e7ae5bc1e..0000000000 --- a/bluesky/_sources/bluesky.plans.pchain.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.pchain -==================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: pchain \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.plan_mutator.txt b/bluesky/_sources/bluesky.plans.plan_mutator.txt deleted file mode 100644 index a8a0983c04..0000000000 --- a/bluesky/_sources/bluesky.plans.plan_mutator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.plan_mutator -========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: plan_mutator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.read.txt b/bluesky/_sources/bluesky.plans.read.txt deleted file mode 100644 index 9cefa4366c..0000000000 --- a/bluesky/_sources/bluesky.plans.read.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.read -================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: read \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.rel_set.txt b/bluesky/_sources/bluesky.plans.rel_set.txt deleted file mode 100644 index fe170fcde6..0000000000 --- a/bluesky/_sources/bluesky.plans.rel_set.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel_set -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_set \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_adaptive_scan.txt b/bluesky/_sources/bluesky.plans.relative_adaptive_scan.txt deleted file mode 100644 index 5ba5e73ab4..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_adaptive_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_adaptive_scan -==================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_adaptive_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_inner_product_scan.txt b/bluesky/_sources/bluesky.plans.relative_inner_product_scan.txt deleted file mode 100644 index b9bf4c4531..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_inner_product_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_inner_product_scan -========================================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_inner_product_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_list_scan.txt b/bluesky/_sources/bluesky.plans.relative_list_scan.txt deleted file mode 100644 index 29145d4387..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_list_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_list_scan -================================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_list_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_log_scan.txt b/bluesky/_sources/bluesky.plans.relative_log_scan.txt deleted file mode 100644 index 9e5d0c2542..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_log_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_log_scan -=============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_log_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_outer_product_scan.txt b/bluesky/_sources/bluesky.plans.relative_outer_product_scan.txt deleted file mode 100644 index 9bbb9c213f..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_outer_product_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_outer_product_scan -========================================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_outer_product_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_scan.txt b/bluesky/_sources/bluesky.plans.relative_scan.txt deleted file mode 100644 index c81a2f152c..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_scan -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_set_decorator.txt b/bluesky/_sources/bluesky.plans.relative_set_decorator.txt deleted file mode 100644 index 3253deec5d..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_set_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_set_decorator -==================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_set_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_set_wrapper.txt b/bluesky/_sources/bluesky.plans.relative_set_wrapper.txt deleted file mode 100644 index 8a85a9bd82..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_set_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_set_wrapper -================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_set_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_spiral.txt b/bluesky/_sources/bluesky.plans.relative_spiral.txt deleted file mode 100644 index 1fc6eb298c..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_spiral.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_spiral -============================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_spiral \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.relative_spiral_fermat.txt b/bluesky/_sources/bluesky.plans.relative_spiral_fermat.txt deleted file mode 100644 index 4ba16ee8b5..0000000000 --- a/bluesky/_sources/bluesky.plans.relative_spiral_fermat.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.relative_spiral_fermat -==================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: relative_spiral_fermat \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.repeater.txt b/bluesky/_sources/bluesky.plans.repeater.txt deleted file mode 100644 index fb4828aa20..0000000000 --- a/bluesky/_sources/bluesky.plans.repeater.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.repeater -====================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: repeater \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.reset_positions_decorator.txt b/bluesky/_sources/bluesky.plans.reset_positions_decorator.txt deleted file mode 100644 index 7e6e24cb05..0000000000 --- a/bluesky/_sources/bluesky.plans.reset_positions_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.reset_positions_decorator -======================================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: reset_positions_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.reset_positions_wrapper.txt b/bluesky/_sources/bluesky.plans.reset_positions_wrapper.txt deleted file mode 100644 index 6607c425ae..0000000000 --- a/bluesky/_sources/bluesky.plans.reset_positions_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.reset_positions_wrapper -===================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: reset_positions_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.run_context.txt b/bluesky/_sources/bluesky.plans.run_context.txt deleted file mode 100644 index 14a16cfda7..0000000000 --- a/bluesky/_sources/bluesky.plans.run_context.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.run_context -========================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: run_context \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.run_decorator.txt b/bluesky/_sources/bluesky.plans.run_decorator.txt deleted file mode 100644 index 0198257f53..0000000000 --- a/bluesky/_sources/bluesky.plans.run_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.run_decorator -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: run_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.run_wrapper.txt b/bluesky/_sources/bluesky.plans.run_wrapper.txt deleted file mode 100644 index 21929f076a..0000000000 --- a/bluesky/_sources/bluesky.plans.run_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.run_wrapper -========================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: run_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.save.txt b/bluesky/_sources/bluesky.plans.save.txt deleted file mode 100644 index 29a78c115c..0000000000 --- a/bluesky/_sources/bluesky.plans.save.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.save -================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: save \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.scan.txt b/bluesky/_sources/bluesky.plans.scan.txt deleted file mode 100644 index 91d45c5503..0000000000 --- a/bluesky/_sources/bluesky.plans.scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.scan -================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.scan_nd.txt b/bluesky/_sources/bluesky.plans.scan_nd.txt deleted file mode 100644 index 81c9fe1f37..0000000000 --- a/bluesky/_sources/bluesky.plans.scan_nd.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.scan_nd -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: scan_nd \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.single_gen.txt b/bluesky/_sources/bluesky.plans.single_gen.txt deleted file mode 100644 index bebf660a47..0000000000 --- a/bluesky/_sources/bluesky.plans.single_gen.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.single_gen -======================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: single_gen \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.sleep.txt b/bluesky/_sources/bluesky.plans.sleep.txt deleted file mode 100644 index fb07df64cd..0000000000 --- a/bluesky/_sources/bluesky.plans.sleep.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.sleep -=================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: sleep \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.spiral.txt b/bluesky/_sources/bluesky.plans.spiral.txt deleted file mode 100644 index 9f2b212619..0000000000 --- a/bluesky/_sources/bluesky.plans.spiral.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.spiral -==================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: spiral \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.spiral_fermat.txt b/bluesky/_sources/bluesky.plans.spiral_fermat.txt deleted file mode 100644 index 166966b0d8..0000000000 --- a/bluesky/_sources/bluesky.plans.spiral_fermat.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.spiral_fermat -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: spiral_fermat \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.stage.txt b/bluesky/_sources/bluesky.plans.stage.txt deleted file mode 100644 index 582611d0ab..0000000000 --- a/bluesky/_sources/bluesky.plans.stage.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.stage -=================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: stage \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.stage_context.txt b/bluesky/_sources/bluesky.plans.stage_context.txt deleted file mode 100644 index b24d412f2a..0000000000 --- a/bluesky/_sources/bluesky.plans.stage_context.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.stage_context -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: stage_context \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.stage_decorator.txt b/bluesky/_sources/bluesky.plans.stage_decorator.txt deleted file mode 100644 index 390b09ff89..0000000000 --- a/bluesky/_sources/bluesky.plans.stage_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.stage_decorator -============================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: stage_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.stage_wrapper.txt b/bluesky/_sources/bluesky.plans.stage_wrapper.txt deleted file mode 100644 index f8758c26c4..0000000000 --- a/bluesky/_sources/bluesky.plans.stage_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.stage_wrapper -=========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: stage_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.stop.txt b/bluesky/_sources/bluesky.plans.stop.txt deleted file mode 100644 index b69f6c9dca..0000000000 --- a/bluesky/_sources/bluesky.plans.stop.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.stop -================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: stop \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.subs_context.txt b/bluesky/_sources/bluesky.plans.subs_context.txt deleted file mode 100644 index 9288800f02..0000000000 --- a/bluesky/_sources/bluesky.plans.subs_context.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.subs_context -========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: subs_context \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.subs_decorator.txt b/bluesky/_sources/bluesky.plans.subs_decorator.txt deleted file mode 100644 index 111560d714..0000000000 --- a/bluesky/_sources/bluesky.plans.subs_decorator.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.subs_decorator -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: subs_decorator \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.subs_wrapper.txt b/bluesky/_sources/bluesky.plans.subs_wrapper.txt deleted file mode 100644 index 1de3540392..0000000000 --- a/bluesky/_sources/bluesky.plans.subs_wrapper.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.subs_wrapper -========================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: subs_wrapper \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.subscribe.txt b/bluesky/_sources/bluesky.plans.subscribe.txt deleted file mode 100644 index 24fb227731..0000000000 --- a/bluesky/_sources/bluesky.plans.subscribe.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.subscribe -======================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: subscribe \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.trigger.txt b/bluesky/_sources/bluesky.plans.trigger.txt deleted file mode 100644 index 2b3c552592..0000000000 --- a/bluesky/_sources/bluesky.plans.trigger.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.trigger -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: trigger \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.trigger_and_read.txt b/bluesky/_sources/bluesky.plans.trigger_and_read.txt deleted file mode 100644 index 9b6605c7e5..0000000000 --- a/bluesky/_sources/bluesky.plans.trigger_and_read.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.trigger_and_read -============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: trigger_and_read \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.tweak.txt b/bluesky/_sources/bluesky.plans.tweak.txt deleted file mode 100644 index 0cae5e83b9..0000000000 --- a/bluesky/_sources/bluesky.plans.tweak.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.tweak -=================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: tweak \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.unmonitor.txt b/bluesky/_sources/bluesky.plans.unmonitor.txt deleted file mode 100644 index a3536c3d1f..0000000000 --- a/bluesky/_sources/bluesky.plans.unmonitor.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.unmonitor -======================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: unmonitor \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.unstage.txt b/bluesky/_sources/bluesky.plans.unstage.txt deleted file mode 100644 index 333af6b3c7..0000000000 --- a/bluesky/_sources/bluesky.plans.unstage.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.unstage -===================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: unstage \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.unsubscribe.txt b/bluesky/_sources/bluesky.plans.unsubscribe.txt deleted file mode 100644 index f9e92026de..0000000000 --- a/bluesky/_sources/bluesky.plans.unsubscribe.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.unsubscribe -========================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: unsubscribe \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.wait.txt b/bluesky/_sources/bluesky.plans.wait.txt deleted file mode 100644 index 0d95ac596b..0000000000 --- a/bluesky/_sources/bluesky.plans.wait.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.wait -================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: wait \ No newline at end of file diff --git a/bluesky/_sources/bluesky.plans.wait_for.txt b/bluesky/_sources/bluesky.plans.wait_for.txt deleted file mode 100644 index e4093a427d..0000000000 --- a/bluesky/_sources/bluesky.plans.wait_for.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.wait_for -====================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: wait_for \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.a2scan.txt b/bluesky/_sources/bluesky.spec_api.a2scan.txt deleted file mode 100644 index ef96edfc1c..0000000000 --- a/bluesky/_sources/bluesky.spec_api.a2scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.a2scan -======================= - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: a2scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.a3scan.txt b/bluesky/_sources/bluesky.spec_api.a3scan.txt deleted file mode 100644 index 52a8e131c1..0000000000 --- a/bluesky/_sources/bluesky.spec_api.a3scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.a3scan -======================= - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: a3scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.afermat.txt b/bluesky/_sources/bluesky.spec_api.afermat.txt deleted file mode 100644 index 9629568704..0000000000 --- a/bluesky/_sources/bluesky.spec_api.afermat.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.afermat -======================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: afermat \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.ascan.txt b/bluesky/_sources/bluesky.spec_api.ascan.txt deleted file mode 100644 index 5d63838786..0000000000 --- a/bluesky/_sources/bluesky.spec_api.ascan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.ascan -====================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: ascan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.aspiral.txt b/bluesky/_sources/bluesky.spec_api.aspiral.txt deleted file mode 100644 index d1c978ab6d..0000000000 --- a/bluesky/_sources/bluesky.spec_api.aspiral.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.aspiral -======================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: aspiral \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.ct.txt b/bluesky/_sources/bluesky.spec_api.ct.txt deleted file mode 100644 index 2b48dcb533..0000000000 --- a/bluesky/_sources/bluesky.spec_api.ct.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.ct -=================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: ct \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.d2scan.txt b/bluesky/_sources/bluesky.spec_api.d2scan.txt deleted file mode 100644 index a89de1e39b..0000000000 --- a/bluesky/_sources/bluesky.spec_api.d2scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.d2scan -======================= - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: d2scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.d3scan.txt b/bluesky/_sources/bluesky.spec_api.d3scan.txt deleted file mode 100644 index f478b39526..0000000000 --- a/bluesky/_sources/bluesky.spec_api.d3scan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.d3scan -======================= - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: d3scan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.dscan.txt b/bluesky/_sources/bluesky.spec_api.dscan.txt deleted file mode 100644 index 2d3c2e64e2..0000000000 --- a/bluesky/_sources/bluesky.spec_api.dscan.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.dscan -====================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: dscan \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.fermat.txt b/bluesky/_sources/bluesky.spec_api.fermat.txt deleted file mode 100644 index a1f6f88d9b..0000000000 --- a/bluesky/_sources/bluesky.spec_api.fermat.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.fermat -======================= - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: fermat \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.mesh.txt b/bluesky/_sources/bluesky.spec_api.mesh.txt deleted file mode 100644 index ebc55a34bb..0000000000 --- a/bluesky/_sources/bluesky.spec_api.mesh.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.mesh -===================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: mesh \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.setup_ct_plot.txt b/bluesky/_sources/bluesky.spec_api.setup_ct_plot.txt deleted file mode 100644 index c72fc07c32..0000000000 --- a/bluesky/_sources/bluesky.spec_api.setup_ct_plot.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.setup_ct_plot -============================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: setup_ct_plot \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.setup_liveraster.txt b/bluesky/_sources/bluesky.spec_api.setup_liveraster.txt deleted file mode 100644 index 028bd93877..0000000000 --- a/bluesky/_sources/bluesky.spec_api.setup_liveraster.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.setup_liveraster -================================= - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: setup_liveraster \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.setup_livetable.txt b/bluesky/_sources/bluesky.spec_api.setup_livetable.txt deleted file mode 100644 index b4a26c66b7..0000000000 --- a/bluesky/_sources/bluesky.spec_api.setup_livetable.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.setup_livetable -================================ - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: setup_livetable \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.setup_peakstats.txt b/bluesky/_sources/bluesky.spec_api.setup_peakstats.txt deleted file mode 100644 index f8e24bab31..0000000000 --- a/bluesky/_sources/bluesky.spec_api.setup_peakstats.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.setup_peakstats -================================ - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: setup_peakstats \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.setup_plot.txt b/bluesky/_sources/bluesky.spec_api.setup_plot.txt deleted file mode 100644 index c698898b42..0000000000 --- a/bluesky/_sources/bluesky.spec_api.setup_plot.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.setup_plot -=========================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: setup_plot \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.spiral.txt b/bluesky/_sources/bluesky.spec_api.spiral.txt deleted file mode 100644 index a9854951ef..0000000000 --- a/bluesky/_sources/bluesky.spec_api.spiral.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.spiral -======================= - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: spiral \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.th2th.txt b/bluesky/_sources/bluesky.spec_api.th2th.txt deleted file mode 100644 index c1404d47a4..0000000000 --- a/bluesky/_sources/bluesky.spec_api.th2th.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.th2th -====================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: th2th \ No newline at end of file diff --git a/bluesky/_sources/bluesky.spec_api.tw.txt b/bluesky/_sources/bluesky.spec_api.tw.txt deleted file mode 100644 index 800b52e1c7..0000000000 --- a/bluesky/_sources/bluesky.spec_api.tw.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.spec_api.tw -=================== - -.. currentmodule:: bluesky.spec_api - -.. autofunction:: tw \ No newline at end of file diff --git a/bluesky/_sources/bluesky.suspenders.SuspendBoolHigh.txt b/bluesky/_sources/bluesky.suspenders.SuspendBoolHigh.txt deleted file mode 100644 index f3812d3bbe..0000000000 --- a/bluesky/_sources/bluesky.suspenders.SuspendBoolHigh.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendBoolHigh -================================== - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendBoolHigh - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendBoolHigh.__init__ - ~SuspendBoolHigh.get_futures - ~SuspendBoolHigh.install - ~SuspendBoolHigh.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendBoolHigh.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.suspenders.SuspendBoolLow.txt b/bluesky/_sources/bluesky.suspenders.SuspendBoolLow.txt deleted file mode 100644 index 355961503f..0000000000 --- a/bluesky/_sources/bluesky.suspenders.SuspendBoolLow.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendBoolLow -================================= - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendBoolLow - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendBoolLow.__init__ - ~SuspendBoolLow.get_futures - ~SuspendBoolLow.install - ~SuspendBoolLow.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendBoolLow.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.suspenders.SuspendCeil.txt b/bluesky/_sources/bluesky.suspenders.SuspendCeil.txt deleted file mode 100644 index 8b77243f87..0000000000 --- a/bluesky/_sources/bluesky.suspenders.SuspendCeil.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendCeil -============================== - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendCeil - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendCeil.__init__ - ~SuspendCeil.get_futures - ~SuspendCeil.install - ~SuspendCeil.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendCeil.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.suspenders.SuspendFloor.txt b/bluesky/_sources/bluesky.suspenders.SuspendFloor.txt deleted file mode 100644 index 4cd5198c20..0000000000 --- a/bluesky/_sources/bluesky.suspenders.SuspendFloor.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendFloor -=============================== - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendFloor - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendFloor.__init__ - ~SuspendFloor.get_futures - ~SuspendFloor.install - ~SuspendFloor.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendFloor.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.suspenders.SuspendInBand.txt b/bluesky/_sources/bluesky.suspenders.SuspendInBand.txt deleted file mode 100644 index 819d0ec0e7..0000000000 --- a/bluesky/_sources/bluesky.suspenders.SuspendInBand.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendInBand -================================ - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendInBand - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendInBand.__init__ - ~SuspendInBand.get_futures - ~SuspendInBand.install - ~SuspendInBand.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendInBand.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/bluesky.suspenders.SuspendOutBand.txt b/bluesky/_sources/bluesky.suspenders.SuspendOutBand.txt deleted file mode 100644 index ea50351ba1..0000000000 --- a/bluesky/_sources/bluesky.suspenders.SuspendOutBand.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendOutBand -================================= - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendOutBand - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendOutBand.__init__ - ~SuspendOutBand.get_futures - ~SuspendOutBand.install - ~SuspendOutBand.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendOutBand.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/callbacks.rst.txt b/bluesky/_sources/callbacks.rst.txt deleted file mode 100644 index e580040d76..0000000000 --- a/bluesky/_sources/callbacks.rst.txt +++ /dev/null @@ -1,1266 +0,0 @@ -Live Visualization and Processing -********************************* - -.. ipython:: python - :suppress: - :okwarning: - - from bluesky import RunEngine - RE = RunEngine({}) - -.. _callbacks: - -Overview of Callbacks ---------------------- - -As the RunEngine executes a plan, it organizes metadata and data into -*Documents,* Python dictionaries organized in a -:doc:`specified but flexible ` way. Each time a new Document is -created, the RunEngine passes it to a list of functions. These functions can do -anything: store the data to disk, print a line of text to the screen, add a -point to a plot, or even transfer the data to a cluster for immediate -processing. These functions are called "callbacks." - -We "subscribe" callbacks to the live stream of Documents coming from the -RunEngine. You can think of a callback as a self-addressed stamped envelope: it -tells the RunEngine, "When you create a Document, send it to this function for -processing." - -Callback functions are run in a blocking fashion: data acquisition cannot -continue until they return. For light tasks like simple plotting or critical -tasks like sending the data to a long-term storage medium, this behavior is -desirable. It is easy to debug and it guarantees that critical errors will be -noticed immediately. But heavy computational tasks --- anything that takes more -than about 0.2 seconds to finish --- should be executed in a separate process -or server so that they do not hold up data acquisition. Bluesky provides nice -tooling for this use case --- see :ref:`zmq_callback`. - -Simplest Working Example ------------------------- - -This example passes every Document to the ``print`` function, printing -each Document as it is generated during data collection. - -.. code-block:: python - - from bluesky.plans import count - from ophyd.sim import det - - RE(count([det]), print) - -The ``print`` function is a blunt instrument; it dumps too much information to -the screen. See :ref:`LiveTable ` below for a more refined option. - -Ways to Invoke Callbacks ------------------------- - -Interactively -+++++++++++++ - -As in the simple example above, pass a second argument to the RunEngine. -For some callback function ``cb``, the usage is: - -.. code-block:: python - - RE(plan(), cb)) - -A working example: - -.. code-block:: python - - from ophyd.sim import det, motor - from bluesky.plans import scan - from bluesky.callbacks import LiveTable - dets = [det] - RE(scan(dets, motor, 1, 5, 5), LiveTable(dets)) - -A *list* of callbacks --- ``[cb1, cb2]`` --- is also accepted; see -:ref:`filtering`, below, for additional options. - -Persistently -++++++++++++ - -The RunEngine keeps a list of callbacks to apply to *every* plan it executes. -For example, the callback that saves the data to a database is typically -invoked this way. For some callback function ``cb``, the usage is: - -.. code-block:: python - - RE.subscribe(cb) - -This step is usually performed in a startup file (i.e., IPython profile). - -.. automethod:: bluesky.run_engine.RunEngine.subscribe - :noindex: - -.. automethod:: bluesky.run_engine.RunEngine.unsubscribe - :noindex: - -.. _subs_decorator: - -Through a plan -++++++++++++++ - -Use the ``subs_decorator`` :ref:`plan preprocessor ` to attach -callbacks to a plan so that they are subscribed every time it is run. - -In this example, we define a new plan, ``plan2``, that adds some callback -``cb`` to some existing plan, ``plan1``. - -.. code-block:: python - - from bluesky.preprocessors import subs_decorator - - @subs_decorator(cb) - def plan2(): - yield from plan1() - -or, equivalently, - -.. code-block:: python - - plan2 = subs_decorator(cb)(plan1) - -For example, to define a variant of ``scan`` that includes a table by default: - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.preprocessors import subs_decorator - - def my_scan(detectors, motor, start, stop, num, *, per_step=None, md=None): - "This plan takes the same arguments as `scan`." - - table = LiveTable([motor] + list(detectors)) - - @subs_decorator(table) - def inner(): - yield from scan(detectors, motor, start, stop, num, - per_step=per_step, md=md) - - yield from inner() - -Callbacks for Visualization & Fitting -------------------------------------- - -.. _livetable: - -LiveTable -+++++++++ - -As each data point is collected (i.e., as each Event Document is generated) a -row is added to the table. Demo: - -.. ipython:: python - - from bluesky.plans import scan - from ophyd.sim import motor, det - from bluesky.callbacks import LiveTable - - RE(scan([det], motor, 1, 5, 5), LiveTable([motor, det])) - -Pass an empty list of columns to show simply 'time' and 'seq_num' (sequence -number). - -.. code-block:: python - - LiveTable([]) - -In the demo above, we passed in a list of *device(s)*, like so: - -.. code-block:: python - - LiveTable([motor]) - -Internally, ``LiveTable`` obtains the name(s) of the field(s) produced by -reading ``motor``. You can do this yourself too: - -.. ipython:: python - - list(motor.describe().keys()) - -In the general case, a device can produce tens or even hundreds of separate -readings, and it can be useful to spell out specific fields rather than a whole -device. - -.. code-block:: python - - # the field 'motor', in quotes, not the device, motor - LiveTable(['motor']) - -In fact, almost all other callbacks (including :ref:`LivePlot`) *require* a -specific field. They will not accept a device because it may have more than one -field. - -.. autoclass:: bluesky.callbacks.LiveTable - -.. warning - - The data in the table is formatted according to its type and the - precision reported by the control system. If you are seeing too - many or too few decimal places, this should be adjusted at the - controls system level. In EPICS, this is typically the ``.PREC`` - field on the record. - -.. _kickers: - -Aside: Making plots update live -+++++++++++++++++++++++++++++++ - -.. note:: - - If you are a user working with a pre-configured setup, you can probably - skip this. Come back if your plots are not appearing / updating. - - This configuration is typically performed in an IPython profile startup - script so that is happens automatically at startup time. - -To make plots live-update while the RunEngine is executing a plan, you have run -this command once. In an IPython terminal, the command is: - -.. code-block:: python - - %matplotlib qt - from bluesky.utils import install_qt_kicker - install_qt_kicker() - -If you are using a Jupyter notebook, the command is: - -.. code-block:: python - - %matplotlib notebook - from bluesky.utils import install_nb_kicker - install_nb_kicker() - -Why? The RunEngine and matplotlib (technically, matplotlib's Qt backend) both -use an event loop. The RunEngine takes control of the event loop while it is -executing a plan. The kicker function periodically "kicks" the Qt event loop so -that the plots can re-draw while the RunEngine is running. - -The ``%matplotlib ...`` command is standard setup, having nothing to do with -bluesky in particular. See -`the relevant section of the IPython documentation `_ -for details. - -.. autofunction:: bluesky.utils.install_kicker -.. autofunction:: bluesky.utils.install_qt_kicker -.. autofunction:: bluesky.utils.install_nb_kicker - -.. _liveplot: - -LivePlot (for scalar data) -++++++++++++++++++++++++++ - -Plot scalars. Example: - -.. code-block:: python - - from bluesky.plans import scan - from ophyd.sim import det, motor - from bluesky.callbacks.mpl_plotting import LivePlot - - RE(scan([det], motor, -5, 5, 30), LivePlot('det', 'motor')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import scan - from ophyd.sim import det, motor - from bluesky.callbacks.mpl_plotting import LivePlot - RE = RunEngine({}) - RE(scan([det], motor, -5, 5, 30), LivePlot('det', 'motor')) - -To customize style, pass in any -`matplotlib line style keyword argument `_. -(``LivePlot`` will pass it through to ``Axes.plot``.) Example: - -.. code-block:: python - - RE(scan([det], motor, -5, 5, 30), - LivePlot('det', 'motor', marker='x', markersize=10, color='red')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import scan - from ophyd.sim import det, motor - from bluesky.callbacks.mpl_plotting import LivePlot - RE = RunEngine({}) - RE(scan([det], motor, -5, 5, 30), - LivePlot('det', 'motor', marker='x', markersize=10, color='red')) - -.. autoclass:: bluesky.callbacks.mpl_plotting.LivePlot - -Live Image -++++++++++ - -.. autoclass:: bluesky.callbacks.broker.LiveImage - -.. _liveraster: - -LiveGrid (gridded heat map) -+++++++++++++++++++++++++++ - -Plot a scalar value as a function of two variables on a regular grid. Example: - -.. code-block:: python - - from bluesky.plans import grid_scan - from ophyd.sim import det4, motor1, motor2 - from bluesky.callbacks.mpl_plotting import LiveGrid - - RE(grid_scan([det4], motor1, -3, 3, 6, motor2, -5, 5, 10, False), - LiveGrid((6, 10), 'det4')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import grid_scan - from ophyd.sim import det4, motor1, motor2 - from bluesky.callbacks.mpl_plotting import LiveGrid - motor1.delay = 0 - motor2.delay = 0 - RE = RunEngine({}) - RE(grid_scan([det4], motor1, -3, 3, 6, motor2, -5, 5, 10, False), - LiveGrid((6, 10), 'det4')) - -.. autoclass:: bluesky.callbacks.mpl_plotting.LiveGrid - -LiveScatter (scattered heat map) -++++++++++++++++++++++++++++++++ - -Plot a scalar value as a function of two variables. Unlike -:class:`bluesky.callbacks.mpl_plotting.LiveGrid`, this does not assume a regular grid. -Example: - -.. code-block:: python - - from bluesky.plans import grid_scan - from ophyd.sim import det5, jittery_motor1, jittery_motor2 - from bluesky.callbacks.mpl_plotting import LiveScatter - - # The 'jittery' example motors won't go exactly where they are told to go. - - RE(grid_scan([det5], - jittery_motor1, -3, 3, 6, - jittery_motor2, -5, 5, 10, False), - LiveScatter('jittery_motor1', 'jittery_motor2', 'det5', - xlim=(-3, 3), ylim=(-5, 5))) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import grid_scan - from ophyd.sim import det5, jittery_motor1, jittery_motor2 - from bluesky.callbacks.mpl_plotting import LiveScatter - RE = RunEngine({}) - RE(grid_scan([det5], - jittery_motor1, -3, 3, 6, - jittery_motor2, -5, 5, 10, False), - LiveScatter('jittery_motor1', 'jittery_motor2', 'det5', - xlim=(-3, 3), ylim=(-5, 5))) - -.. autoclass:: bluesky.callbacks.mpl_plotting.LiveScatter - -LiveFit -+++++++ - -Perform a nonlinear least squared best fit to the data with a user-defined -model function. The function can depend on any number of independent variables. -We integrate with the package -`lmfit `_, which provides a nice -interface for NLS minimization. - -In this example, we fit a Gaussian to detector readings as a function of motor -position. First, define a Gaussian function, create an ``lmfit.Model`` from it, -and provide initial guesses for the parameters. - -.. code-block:: python - - import numpy as np - import lmfit - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - -The guesses can be given as plain numbers or as ``lmfit.Parameter`` objects, as -in the case of 'sigma' above, to specify constraints. - -To integrate with the bluesky we need to provide: - -* the field with the dependent variable (in this example, ``'noisy_det'``) -* a mapping between the name(s) of independent variable(s) in - the function (``'x'``) to the corresponding field(s) in the data - (``'motor'``) -* any initial guesses expected by the model (defined above) - -.. code-block:: python - - from bluesky.plans import scan - from ophyd.sim import motor, noisy_det - from bluesky.callbacks import LiveFit - - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - - RE(scan([noisy_det], motor, -1, 1, 100), lf) - # best-fit values for 'A', 'sigma' and 'x0' are in lf.result.values - -The fit results are accessible in the ``result`` attribute of the callback. -For example, the center of the Gaussian is ``lf.result.values['x0']``. This -could be used in a next step, like so: - -.. code-block:: python - - x0 = lf.result.values['x0'] - RE(scan([noisy_det], x0 - 1, x0 + 1, 100)) - -Refer the -`lmfit documentation `_ -for more about ``result``. - -This example uses a model with two independent variables, x and y. - -.. code-block:: python - - from ophyd.sim import motor1, motor2, det4 - - def gaussian(x, y, A, sigma, x0, y0): - return A*np.exp(-((x - x0)**2 + (y - y0)**2)/(2 * sigma**2)) - - # Specify the names of the independent variables to Model. - model = lmfit.Model(gaussian, ['x', 'y']) - - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2, - 'y0': 0.3} - - lf = LiveFit(model, 'det4', {'x': 'motor1', 'y': 'motor2'}, init_guess) - - # Scan a 2D mesh. - RE(grid_scan([det4], motor1, -1, 1, 20, motor2, -1, 1, 20, False), - lf) - -By default, the fit is recomputed every time a new data point is available. See -the API documentation below for other options. Fitting does not commence until -the number of accumulated data points is equal to the number of free parameters -in the model. - -.. autoclass:: bluesky.callbacks.LiveFit - -LiveFitPlot -+++++++++++ - -This is a variation on ``LivePlot`` that plots the best fit curve from -``LiveFit``. It applies to 1D model functions only. - -Repeating the example from ``LiveFit`` above, adding a plot: - -.. code-block:: python - - # same as above... - - import numpy as np - import lmfit - from bluesky.plans import scan - from ophyd.sim import motor, noisy_det - from bluesky.callbacks import LiveFit - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - - # now add the plot... - - from bluesky.callbacks.mpl_plotting import LiveFitPlot - lpf = LiveFitPlot(lf, color='r') - - RE(scan([noisy_det], motor, -1, 1, 100), lfp) - - # Notice that we did'nt need to subscribe lf directly, just lfp. - # But, as before, the results are in lf.result. - -.. plot:: - - import numpy as np - import lmfit - from bluesky.plans import scan - from ophyd.sim import motor, noisy_det - from bluesky.callbacks import LiveFit - from bluesky.callbacks.mpl_plotting import LiveFitPlot - from bluesky import RunEngine - - RE = RunEngine({}) - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - lfp = LiveFitPlot(lf, color='r') - - RE(scan([noisy_det], motor, -1, 1, 100), lfp) - -We can use the standard ``LivePlot`` to show the data on the same axes. -Notice that they can styled independently. - -.. code-block:: python - - import matplotlib.pyplot as plt - - fig, ax = plt.subplots() # explitly create figure, axes to use below - lfp = LiveFitPlot(lf, ax=ax, color='r') - lp = LivePlot('noisy_det', 'motor', ax=ax, marker='o', linestyle='none') - - RE(scan([noisy_det], motor, -1, 1, 100), [lp, lfp]) - -.. plot:: - - import numpy as np - import lmfit - from bluesky.plans import scan - from ophyd.sim import motor, noisy_det - from bluesky.callbacks import LiveFit - from bluesky.callbacks.mpl_plotting import LivePlot, LiveFitPlot - from bluesky import RunEngine - - RE = RunEngine({}) - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - - import matplotlib.pyplot as plt - fig, ax = plt.subplots() - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - lfp = LiveFitPlot(lf, ax=ax, color='r') - lp = LivePlot('noisy_det', 'motor', ax=ax, marker='o', linestyle='none') - - RE(scan([noisy_det], motor, -1, 1, 50), [lfp, lp]) - plt.draw() - -.. autoclass:: bluesky.callbacks.mpl_plotting.LiveFitPlot - -PeakStats -++++++++++ - -Compute statistics of peak-like data. Example: - -.. code-block:: python - - from bluesky.callbacks.fitting import PeakStats - from ophyd.sim import motor, det - from bluesky.plans import scan - - ps = PeakStats('motor', 'det') - RE(scan([det], motor, -5, 5, 10), ps) - -Now attributes of ``ps``, documented below, contain various peak statistics. -There is also a convenience function for plotting: - -.. code-block:: python - - from bluesky.callbacks.mpl_plotting import plot_peak_stats - - plot_peak_stats(ps) - -.. plot:: - - from bluesky import RunEngine - from bluesky.callbacks.fitting import PeakStats - from bluesky.callbacks.mpl_plotting import plot_peak_stats - from ophyd.sim import motor, det - from bluesky.plans import scan - - RE = RunEngine({}) - ps = PeakStats('motor', 'det') - RE(scan([det], motor, -5, 5, 10), ps) - plot_peak_stats(ps) - -.. autoclass:: bluesky.callbacks.fitting.PeakStats -.. autofunction:: bluesky.callbacks.mpl_plotting.plot_peak_stats - -.. _best_effort_callback: - -Best-Effort Callback --------------------- - -.. warning:: - - This is a new, experimental feature. It will likely be changed in future - releases in a way that is not backward-compatible. - -This is meant to be permanently subscribed to the RunEngine like so: - -.. code-block:: python - - # one-time configuration - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - RE.subscribe(bec) - -It provides best-effort plots and visualization for *any* plan. It uses the -'hints' key provided by the plan, if present. (See the source code of the -plans in :mod:`bluesky.plans` for examples.) - -.. ipython:: python - :suppress: - - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - RE.subscribe(bec) - -.. ipython:: python - - from ophyd.sim import det1, det2 - from bluesky.plans import scan - - dets = [det1, det2] - - RE(scan(dets, motor, 1, 5, 5)) # automatically prints table, shows plot - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import scan - from ophyd.sim import det, motor - from bluesky.callbacks.best_effort import BestEffortCallback - RE = RunEngine({}) - bec = BestEffortCallback() - RE.subscribe(bec) - RE(scan([det], motor, 1, 5, 5)) - -Use these methods to toggle on or off parts of the functionality. - -.. currentmodule:: bluesky.callbacks.best_effort - -.. autosummary:: - :toctree: generated - - BestEffortCallback - BestEffortCallback.enable_heading - BestEffortCallback.disable_heading - BestEffortCallback.enable_table - BestEffortCallback.disable_table - BestEffortCallback.enable_baseline - BestEffortCallback.disable_baseline - BestEffortCallback.enable_plots - BestEffortCallback.disable_plots - -Blacklist plotting certain streams using the ``bec.noplot_streams`` attribute, -which is a list of stream names. The blacklist is set to ``['baseline']`` by -default. - -The attribute ``bec.overplot`` can be used to control whether line plots for -subsequent runs are plotted on the same axes. It is ``True`` by default. -Overplotting only occurs if the names of the axes are the same from one plot -to the next. - -Peak Stats -++++++++++ - -For each plot, simple peak-fitting is performed in the background. Of -course, it may or may not be applicable depending on your data, and it is -not shown by default. To view fitting annotations in a plot, click the -plot area and press Shift+P. (Lowercase p is a shortcut for -"panning" the plot.) - -To access the peak-fit statistics programmatically, use ``bec.peaks``. - -.. _hints: - -Hints -+++++ - -The best-effort callback aims to print and plot useful information without -being overwhelmingly comprehensive. Its usefulness is improved and tuned by the -``hints`` attribute on devices (if available) and ``hints`` metadata injected -by plans (if available). If either or both of these are not available, the -best-effort callback still makes a best effort to display something useful. - -The contents of hints *do not at all affect what data is saved*. The content -only affect what is displayed automatically by the best-effort callback and -other tools that opt to look at the hints. Additional callbacks may still be -set up for live or *post-facto* visualization or processing that do more -specific things without relying on hints. - -The ``hints`` attribute or property on devices is a dictionary with the key -``'fields'`` mapped to a list of fields. - -On movable devices such as motors or temperature controllers, these fields are -expected to comprise the independent axes of the device. A motor that reads -the fields ``['x', 'x_setpoint']`` might provide the hint ``{'fields': ['x']}`` -to indicate that it has one independent axis and that the field ``x`` is the best -representation of its value. - -A readable device might report many fields like -``['chan1', 'chan2', 'chan3', 'chan4', 'chan5']`` but perhaps only a couple are -usually interesting. A useful hint might narrow them down to -``{'fields': ['chan1', 'chan2']}`` so that a "best-effort" plot does not -display an overwhelming amount of information. - -The hints provided by the devices are read by the RunEngine and collated in the -:doc:`Event Descriptor documents `. - -The plans generally know which devices are being used as dependent and -independent variables (i.e., which are being "scanned" over), and they may -provide this information via a ``'hints'`` metadata key that they inject into -the start document along with the rest of their metadata. Examples: - -.. code-block:: python - - # The pattern is - # {'dimensions': [(fields, stream_name), (fields, stream_name), ...]} - - # a scan over time - {'dimensions': [(('time',), 'primary')]} - - # a one-dimensional scan - {'dimensions': [(motor.hints['fields'], 'primary')]} - - # a two-dimensional scan - {'dimensions': [(x_motor.hints['fields'], 'primary'), - (y_motor.hints['fields'], 'primary')]} - - # an N-dimensional scan - {'dimensions': [(motor.hints['fields'], 'primary') for motor in motors]} - -It's possible to adjust hints interactively, but they are generally intended to -be set in a startup file. Err on the side of displaying more information than -you need to see, and you will rarely need to adjust them. - -Plans may also hint that their data is sampled on a regular rectangular grid -via the hint ``{'gridding': 'rectilinear'}``. This is useful, for example, for -decided whether to visualize 2D data with LiveGrid or with LiveScatter. - -.. _export: - -Callback for Export -------------------- - -Exporting Image Data as TIFF Files -++++++++++++++++++++++++++++++++++ - -First, compose a filename template. The template can include metadata or event -data from the scan. - -.. code-block:: python - - # a template that includes the scan ID and sequence number in each filename - template = "output_dir/{start[scan_id]}_{event[seq_num]}.tiff" - - # a template that sorts files into directories based user and scan ID - template = "output_dir/{start[user]}/{start[scan_id]}/{event[seq_num]}.tiff" - - # a more complex template includes actual measurements in the filenames - template = ("output_dir/{start[scan_id]}_{start[sample_name]}_" - "{event[data][temperature]}_{event[seq_num]}.tiff") - -Above, we are using a Python language feature called format strings. Notice -that inside the curly brackets we don't use quotes around the key names; it's -``{event[seq_num]}`` not ``{event['seq_num']}``. - -If each image data point is actually a stack of 2D image planes, the template -must also include ``{i}``, which will count through the image planes in the -stack. - -.. note:: - - Most metadata comes from the "start" document, hence ``start.scan_id`` - above. Review the :doc:`documents` section for details. - -Create a callback that exports TIFFs using your template. - -.. code-block:: python - - from bluesky.callbacks.broker import LiveTiffExporter - - exporter = LiveTiffExporter('image', template) - -Finally, to export all the images from a run when it finishes running, wrap the -exporter in ``post_run`` and subscribe. - -.. code-block:: python - - from bluesky.callbacks.broker import post_run - - RE.subscribe(post_run(exporter)) - -It also possible to write TIFFs live, hence the name ``LiveTiffExporter``, but -there is an important disadvantage to doing this subscription in the same -process: progress of the experiment may be intermittently slowed while data is -written to disk. In some circumstances, this affect on the timing of the -experiment may not be acceptable. - -.. code-block:: python - - RE.subscribe(exporter) - -There are more configuration options available, as given in detail below. It is -recommended to use these expensive callbacks in a separate process. - -.. autoclass:: bluesky.callbacks.broker.LiveTiffExporter - -Export All Data and Metadata in an HDF5 File -++++++++++++++++++++++++++++++++++++++++++++ - -A Stop Document is emitted at the end of every run. Subscribe to it, using it -as a cue to load the dataset via the DataBroker and export an HDF5 file -using `suitcase `_. - - -Working example: - -.. code-block:: python - - from databroker import DataBroker as db - import suitcase - - def suitcase_as_callback(name, doc): - if name != 'stop': - return - run_start_uid = doc['run_start'] - header = db[run_start_uid] - filename = '{}.h5'.format(run_start_uid) - suitcase.export(header, filename) - - RE.subscribe(suitcase_as_callback, 'stop') - -Export Metadata to the Olog -+++++++++++++++++++++++++++ - -The `Olog `_ ("operational log") is an -electronic logbook. We can use a callback to automatically generate log entries -at the beginning of a run. The Python interface to Olog is not straightforward, -so there is some boilerplate: - -.. code-block:: python - - from functools import partial - from pyOlog import SimpleOlogClient - from bluesky.callbacks.olog import logbook_cb_factory - - # Set up the logbook. This configures bluesky's summaries of - # data acquisition (scan type, ID, etc.). - - LOGBOOKS = ['Data Acquisition'] # list of logbook names to publish to - simple_olog_client = SimpleOlogClient() - generic_logbook_func = simple_olog_client.log - configured_logbook_func = partial(generic_logbook_func, logbooks=LOGBOOKS) - - cb = logbook_cb_factory(configured_logbook_func) - RE.subscribe(cb, 'start') - -The module ``bluesky.callbacks.olog`` includes some templates that format the -data from the 'start' document into a readable log entry. You can also write -customize templates and pass them to ``logbook_cb_factory``. - -You may specify a custom template. Here is a very simple example; see the -`source code `_ -for a more complex example (the default template). - -.. code-block:: python - - CUSTOM_TEMPLATE = """ - My Log Entry - - {{ start.plan_name }} - Detectors: {{ start.detectors }} - """ - - # Do same boilerplate above to set up configured_logbook_func. Then: - cb = logbook_cb_factory(configured_logbook_func, - desc_template=CUSTOM_TEMPLATE) - -You may also specify a variety of different templates that are suitable for -different kinds of plans. The callback will use the ``'plan_name'`` field to -determine which template to use. - -.. code-block:: python - - # a template for a 'count' plan (which has no motors) - COUNT_TEMPLATE = """ - Plan Name: {{ start.plan_name }} - Detectors: {{ start.detectors }} - """ - - # a template for any plan with motors - SCAN_TEMPLATE = """ - Plan Name: {{ start.plan_name }} - Detectors: {{ start.detectors }} - Motor(s): {{ start.motors }} - """ - - templates = {'count': COUNT_TEMPLATE, - 'scan': SCAN_TEMPLATE, - 'rel_scan': SCAN_TEMPLATE} - - # Do same boilerplate above to set up configured_logbook_func. Then: - cb = logbook_cb_factory(configured_logbook_func, - desc_dispatch=templates) - -.. autofunction:: bluesky.callbacks.olog.logbook_cb_factory - -Verify Data Has Been Saved --------------------------- - -The following verifies that all Documents and external files from a run have -been saved to disk and are accessible from the DataBroker. It prints a message -indicating success or failure. - -Note: If the data collection machine is not able to access the machine where -some external data is being saved, it will indicate failure. This can be a -false alarm. - -.. code-block:: python - - from bluesky.callbacks.broker import post_run, verify_files_saved - - RE.subscribe(post_run(verify_files_saved)) - -.. _debugging_callbacks: - -Ignoring Callback Exceptions ----------------------------- - -If an exception is raised while processing a callback, the error can interrupt -data collection. Sometimes, this is good: if, for example, the callback that is -saving your data encounters an error, you want to know immediately rather than -continuing to *think* you are collecting data when in fact it is being lost. -But in many situations, such as visualization or first-pass data processing, it -is usually better for data collection to proceed even if a callback fails. -These decorators may be used to wrap callbacks so that any errors they -encounter are converted to log messages. - -.. autofunction:: bluesky.callbacks.core.make_callback_safe - -.. autofunction:: bluesky.callbacks.core.make_class_safe - -It is also possible to configure the RunEngine to ignore *all* callback -exceptions globally, but this feature is not recommended. - -.. code-block:: python - - RE.ignore_callback_exceptions = False - -.. versionchanged:: 0.6.4 - - In bluesky version 0.6.4 (September 2016) the default value was changed from - ``True`` to ``False``. - -.. _filtering: - -Filtering by Document Type --------------------------- - -There are four "subscriptions" that a callback to receive documents from: - -* 'start' -* 'stop' -* 'event' -* 'descriptor' - -Additionally, there is an 'all' subscription. - -The command: - -.. code-block:: python - - RE(plan(), cb) - -is a shorthand that is normalized to ``{'all': [cb]}``. To receive only certain -documents, specify the document routing explicitly. Examples: - -.. code-block:: python - - RE(plan(), {'start': [cb]} - RE(plan(), {'all': [cb1, cb2], 'start': [cb3]}) - -The ``subs_decorator``, presented above, accepts the same variety of inputs. - -Writing Custom Callbacks ------------------------- - -Any function that accepts a Python dictionary as its argument can be used as -a callback. Refer to simple examples above to get started. - -Two Simple Custom Callbacks -+++++++++++++++++++++++++++ - -These simple examples illustrate the concept and the usage. - -First, we define a function that takes two arguments - -#. the name of the Document type ('start', 'stop', 'event', or 'descriptor') -#. the Document itself, a dictionary - -This is the *callback*. - -.. ipython:: python - - def print_data(name, doc): - print("Measured: %s" % doc['data']) - -Then, we tell the RunEngine to call this function on each Event Document. -We are setting up a *subscription*. - -.. ipython:: python - - from ophyd.sim import det - from bluesky.plans import count - - RE(count([det]), {'event': print_data}) - -Each time the RunEngine generates a new Event Document (i.e., data point) -``print_data`` is called. - -There are five kinds of subscriptions matching the four kinds of Documents plus -an 'all' subscription that receives all Documents. - -* 'start' -* 'descriptor' -* 'event' -* 'stop' -* 'all' - -We can use the 'stop' subscription to trigger automatic end-of-run activities. -For example: - -.. code-block:: python - - def celebrate(name, doc): - # Do nothing with the input; just use it as a signal that run is over. - print("The run is finished!") - -Let's use both ``print_data`` and ``celebrate`` at once. - -.. code-block:: python - - RE(plan(), {'event': print_data, 'stop': celebrate}) - -Using multiple document types -+++++++++++++++++++++++++++++ - -Some tasks use only one Document type, but we often need to use more than one. -For example, LiveTable uses 'start' kick off the creation of a fresh table, -it uses 'event' to see the data, and it uses 'stop' to draw the bottom border. - -A convenient pattern for this kind of subscription is a class with a method -for each Document type. - -.. code-block:: python - - from bluesky.callbacks import CallbackBase - - class MyCallback(CallbackBase): - def start(self, doc): - print("I got a new 'start' Document") - # Do something - def descriptor(self, doc): - print("I got a new 'descriptor' Document") - # Do something - def event(self, doc): - print("I got a new 'event' Document") - # Do something - def stop(self, doc): - print("I got a new 'stop' Document") - # Do something - -The base class, ``CallbackBase``, takes care of dispatching each Document to -the corresponding method. If your application does not need all four, you may -simple omit methods that aren't required. - -.. _zmq_callback: - -Subscriptions in Separate Processes or Host with 0MQ ----------------------------------------------------- - -Because subscriptions are processed during a scan, it's possible that they can -slow down data collection. We mitigate this by making the subscriptions run in -a separate process. - -In the main process, where the RunEngine is executing the plan, a ``Publisher`` -is created. It subscribes to the RunEngine. It serializes the documents it -receives and it sends them over a socket to a 0MQ proxy which rebroadcasts the -documents to any number of other processes or machines on the network. - -These other processes or machines set up a ``RemoteDispatcher`` which connects -to the proxy receives the documents, and then runs callbacks just as they would -be run if they were in the local ``RunEngine`` process. - -Multiple Publishers (each with its own RunEngine) can send documents to the -same proxy. RemoteDispatchers can filter the document stream based a byte -prefix. - -Minimal Example -+++++++++++++++ - -Start a 0MQ proxy using the CLI packaged with bluesky. It requires two ports as -arguments. - -.. code-block:: bash - - bluesky-0MQ-proxy 5577 5578 - -Alternatively, you can start the proxy using a Python API: - -.. code-block:: python - - from bluesky.callbacks.zmq import Proxy - proxy = Proxy(5577, 5578) - proxy.start() - -Start a callback that will receive documents from the proxy and, in this -simple example, just print them. - -.. code-block:: python - - from bluesky.callbacks.zmq import RemoteDispatcher - d = RemoteDispatcher('localhost:5578') - d.subscribe(print) - - # when done subscribing things and ready to use: - d.start() # runs event loop forever - -As `described above `_, if you want to use any live-updating plots, -you will need to install a "kicker". It needs to be installed on the same -event loop used by the RemoteDispatcher, like so, and it must be done before -calling ``d.start()``. - -.. code-block:: python - - from bluesky.utils import install_qt_kicker - install_qt_kicker(loop=d.loop) - -In a Jupyter notebook, replace ``install_qt_kicker`` with -``install_nb_kicker``. - -On the machine/process where you want to collect data, hook up a subscription -to publish documents to the proxy. - -.. code-block:: python - - # Create a RunEngine instance (or, of course, use your existing one). - from bluesky import RunEngine, Msg - RE = RunEngine({}) - - from bluesky.callbacks.zmq import Publisher - publisher = Publisher('localhost:5577') - RE.subscribe(publisher) - -Finally, execute a plan with the RunEngine. As a result, the callback in the -RemoteDispatcher should print the documents generated by this plan. - -Publisher / RemoteDispatcher API -++++++++++++++++++++++++++++++++ - -.. autoclass:: bluesky.callbacks.zmq.Proxy -.. autoclass:: bluesky.callbacks.zmq.Publisher -.. autoclass:: bluesky.callbacks.zmq.RemoteDispatcher - - -Secondary Event Stream ----------------------- -For certain applications, it may desirable to interpret event documents as -they are created instead of waiting for them to reach offline storage. In order -to keep this information completely quarantined from the raw data, the -:class:`.LiveDispatcher` presents a completely unique stream that can be -subscribed to using the same syntax as the RunEngine. - -In the majority of applications of :class:`.LiveDispatcher`, it is expected -that subclasses are created to implement online analysis. This secondary event -stream can be displayed and saved offline using the same callbacks that you -would use to display the raw data. - -Below is an example using the `streamz -`_ library to average a number of -events together. The callback can be configured by looking at the start -document metadata, or at initialization time. Events are then received and -stored by the ``streamz`` network and a new averaged event is emitted when the -correct number of events are in the cache. The important thing to note here is -that the analysis only handles creating new ``data`` keys, but the descriptors, -sequence numbering and event ids are all handled by the base `LiveDispatcher` -class. - -.. code-block:: python - - class AverageStream(LiveDispatcher): - """Stream that averages data points together""" - def __init__(self, n=None): - self.n = n - self.in_node = None - self.out_node = None - self.averager = None - super().__init__() - - def start(self, doc): - """ - Create the stream after seeing the start document - - The callback looks for the 'average' key in the start document to - configure itself. - """ - # Grab the average key - self.n = doc.get('average', self.n) - # Define our nodes - if not self.in_node: - self.in_node = streamz.Source(stream_name='Input') - - self.averager = self.in_node.partition(self.n) - - def average_events(cache): - average_evt = dict() - desc_id = cache[0]['descriptor'] - # Check that all of our events came from the same configuration - if not all([desc_id == evt['descriptor'] for evt in cache]): - raise Exception('The events in this bundle are from ' - 'different configurations!') - # Use the last descriptor to avoid strings and objects - data_keys = self.raw_descriptors[desc_id]['data_keys'] - for key, info in data_keys.items(): - # Information from non-number fields is dropped - if info['dtype'] in ('number', 'array'): - # Average together - average_evt[key] = np.mean([evt['data'][key] - for evt in cache], axis=0) - return {'data': average_evt, 'descriptor': desc_id} - - self.out_node = self.averager.map(average_events) - self.out_node.sink(self.process_event) - super().start(doc) - - def event(self, doc): - """Send an Event through the stream""" - self.in_node.emit(doc) - - def stop(self, doc): - """Delete the stream when run stops""" - self.in_node = None - self.out_node = None - self.averager = None - super().stop(doc) - - -LiveDispatcher API -++++++++++++++++++ -.. autoclass:: bluesky.callbacks.stream.LiveDispatcher - :members: diff --git a/bluesky/_sources/callbacks.txt b/bluesky/_sources/callbacks.txt deleted file mode 100644 index 456e6005cf..0000000000 --- a/bluesky/_sources/callbacks.txt +++ /dev/null @@ -1,983 +0,0 @@ -Live Visualization and Processing -********************************* - -.. ipython:: python - :suppress: - :okwarning: - - from bluesky import RunEngine - RE = RunEngine({}) - -.. _callbacks: - -Overview of Callbacks ---------------------- - -As the RunEngine executes a plan, it organizes metadata and data into -*Documents,* Python dictionaries organized in a `specified but flexible -`__ way. -Each time a new Document is created, the RunEngine passes it to a list of -functions. These functions can do anything: store the data to disk, print a -line of text to the screen, add a point to a plot, or even transfer the data to -a cluster for immediate processing. These functions are called "callbacks." - -We "subscribe" callbacks to the live stream of Documents coming from the -RunEngine. You can think of a callback as a self-addressed stamped envelope: it -tells the RunEngine, "When you create a Document, send it to this function for -processing." - -Simplest Working Example ------------------------- - -This example passes every Document to the ``print`` function, printing -each Document as it is generated during data collection. - -.. code-block:: python - - from bluesky.plans import count - from bluesky.examples import det - - RE(count([det]), print) - -The ``print`` function is a blunt instrument; it dumps too much information to -the screen. See :ref:`LiveTable ` below for a more refined option. - -Ways to Invoke Callbacks ------------------------- - -Interactively -+++++++++++++ - -As in the simple example above, pass a second argument to the RunEngine. -For some callback function ``cb``, the usage is: - -.. code-block:: python - - RE(plan(), cb)) - -A working example: - -.. code-block:: python - - from bluesky.examples import det, motor - from bluesky.plans import scan - from bluesky.callbacks import LiveTable - dets = [det] - RE(scan(dets, motor, 1, 5, 5), LiveTable(dets)) - -A *list* of callbacks --- ``[cb1, cb2]`` --- is also accepted; see -:ref:`filtering`, below, for additional options. - -Persistently -++++++++++++ - -The RunEngine keeps a list of callbacks to apply to *every* plan it executes. -For example, the callback that saves the data to a database is typically -invoked this way. For some callback function ``cb``, the usage is: - -.. code-block:: python - - RE.subscribe('all', cb) - -This step is usually performed in a startup file (i.e., IPython profile). - -The method ``RunEngine.subscribe`` is an alias for this method: - -.. automethod:: bluesky.run_engine.Dispatcher.subscribe - -The method ``RunEngine.unsubscribe`` is an alias for this method: - -.. automethod:: bluesky.run_engine.Dispatcher.unsubscribe - -.. _subs_decorator: - -Through a plan -++++++++++++++ - -Use the ``subs_decorator`` :ref:`plan preprocessor ` to attach -callbacks to a plan so that they are subscribed every time it is run. - -In this example, we define a new plan, ``plan2``, that adds some callback -``cb`` to some existing plan, ``plan1``. - -.. code-block:: python - - from bluesky.plans import subs_decorator - - @subs_decorator(cb) - def plan2(): - yield from plan1() - -or, equivalently, - -.. code-block:: python - - plan2 = subs_decorator(cb)(plan1) - -For example, to define a variant of ``scan`` that includes a table by default: - -.. code-block:: python - - from bluesky.plans import scan, subs_decorator - - def my_scan(detectors, motor, start, stop, num, *, per_step=None, md=None): - "This plan takes the same arguments as `scan`." - - table = LiveTable([motor] + list(detectors)) - - @subs_decorator(table) - def inner(): - yield from scan(detectors, motor, start, stop, num, - per_step=per_step, md=md) - - yield from inner() - -Callbacks for Visualization & Fitting -------------------------------------- - -.. _livetable: - -LiveTable -+++++++++ - -As each data point is collected (i.e., as each Event Document is generated) a -row is added to the table. Demo: - -.. ipython:: python - - from bluesky.plans import scan - from bluesky.examples import motor, det - from bluesky.callbacks import LiveTable - - RE(scan([det], motor, 1, 5, 5), LiveTable([motor, det])) - -Pass an empty list of columns to show simply 'time' and 'seq_num' (sequence -number). - -.. code-block:: python - - LiveTable([]) - -In the demo above, we passed in a list of *device(s)*, like so: - -.. code-block:: python - - LiveTable([motor]) - -Internally, ``LiveTable`` obtains the name(s) of the field(s) produced by -reading ``motor``. You can do this yourself too: - -.. ipython:: python - - list(motor.describe().keys()) - -In the general case, a device can produce tens or even hundreds of separate -readings, and it can be useful to spell out specific fields rather than a whole -device. - -.. code-block:: python - - # the field 'motor', in quotes, not the device, motor - LiveTable(['motor']) - -In fact, almost all other callbacks (including :ref:`LivePlot`) *require* a -specific field. They will not accept a device because it may have more than one -field. - -.. autoclass:: bluesky.callbacks.LiveTable - -.. _kickers: - -Aside: Making plots update live -+++++++++++++++++++++++++++++++ - -.. note:: - - If you are a user working with a pre-configured setup, you can probably - skip this. Come back if your plots are not appearing / updating. - - This configuration is typically performed in an IPython profile startup - script so that is happens automatically at startup time. - -To make plots live-update while the RunEngine is executing a plan, you have run -this command once. In an IPython terminal, the command is: - -.. code-block:: python - - %matplotlib qt - from bluesky.utils import install_qt_kickcer - install_qt_kicker() - -If you are using a Jupyter notebook, the command is: - -.. code-block:: python - - %matplotlib notebook - from bluesky.utils import install_nb_kickcer - install_nb_kicker() - -Why? The RunEngine and matplotlib (technically, matplotlib's Qt backend) both -use an event loop. The RunEngine takes control of the event loop while it is -executing a plan. The kicker function periodically "kicks" the Qt event loop so -that the plots can re-draw while the RunEngine is running. - -The ``%matplotlib ...`` command is standard setup, having nothing to do with -bluesky in particular. See -`the relevant section of the IPython documentation `_ -for details. - -.. _liveplot: - -LivePlot (for scalar data) -++++++++++++++++++++++++++ - -Plot scalars. Example: - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.examples import det, motor - from bluesky.callbacks import LivePlot - - RE(scan([det], motor, -5, 5, 30), LivePlot('det', 'motor')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import scan - from bluesky.examples import det, motor - from bluesky.callbacks import LivePlot - RE = RunEngine({}) - RE(scan([det], motor, -5, 5, 30), LivePlot('det', 'motor')) - -To customize style, pass in any -`matplotlib line style keyword argument `_. -(``LivePlot`` will pass it through to ``Axes.plot``.) Example: - -.. code-block:: python - - RE(scan([det], motor, -5, 5, 30), - LivePlot('det', 'motor', marker='x', markersize=10, color='red')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import scan - from bluesky.examples import det, motor - from bluesky.callbacks import LivePlot - RE = RunEngine({}) - RE(scan([det], motor, -5, 5, 30), - LivePlot('det', 'motor', marker='x', markersize=10, color='red')) - -.. autoclass:: bluesky.callbacks.LivePlot - -Live Image -++++++++++ - -.. autoclass:: bluesky.callbacks.broker.LiveImage - -.. _liveraster: - -LiveRaster (gridded heat map) -+++++++++++++++++++++++++++++ - -Plot a scalar value as a function of two variables on a regular grid. Example: - -.. code-block:: python - - from bluesky.plans import outer_product_scan - from bluesky.examples import det4, motor1, motor2 - from bluesky.callbacks import LiveRaster - - RE(outer_product_scan([det4], motor1, -3, 3, 6, motor2, -5, 5, 10, False), - LiveRaster((6, 10), 'det4')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import outer_product_scan - from bluesky.examples import det4, motor1, motor2 - from bluesky.callbacks import LiveRaster - motor1._fake_sleep = 0 - motor2._fake_sleep = 0 - RE = RunEngine({}) - RE(outer_product_scan([det4], motor1, -3, 3, 6, motor2, -5, 5, 10, False), - LiveRaster((6, 10), 'det4')) - -.. autoclass:: bluesky.callbacks.LiveRaster - -LiveMesh (scattered heat map) -+++++++++++++++++++++++++++++ - -Plot a scalar value as a function of two variables. Unlike -:class:`bluesky.callbacks.LiveRaster`, this does not assume a regular grid. -Example: - -.. code-block:: python - - from bluesky.plans import outer_product_scan - from bluesky.examples import det5, jittery_motor1, jittery_motor2 - from bluesky.callbacks import LiveMesh - - # The 'jittery' example motors won't go exactly where they are told to go. - - RE(outer_product_scan([det5], - jittery_motor1, -3, 3, 6, - jittery_motor2, -5, 5, 10, False), - LiveMesh('jittery_motor1', 'jittery_motor2', 'det5', - xlim=(-3, 3), ylim=(-5, 5))) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import outer_product_scan - from bluesky.examples import det5, jittery_motor1, jittery_motor2 - from bluesky.callbacks import LiveMesh - RE = RunEngine({}) - RE(outer_product_scan([det5], - jittery_motor1, -3, 3, 6, - jittery_motor2, -5, 5, 10, False), - LiveMesh('jittery_motor1', 'jittery_motor2', 'det5', - xlim=(-3, 3), ylim=(-5, 5))) - -.. autoclass:: bluesky.callbacks.LiveMesh - -LiveFit -+++++++ - -Perform a nonlinear least squared best fit to the data with a user-defined -model function. The function can depend on any number of independent variables. -We integrate with the package -`lmfit `_, which provides a nice -interface for NLS minimization. - -In this example, we fit a Gaussian to detector readings as a function of motor -position. First, define a Gaussian function, create an ``lmfit.Model`` from it, -and provide initial guesses for the parameters. - -.. code-block:: python - - import numpy as np - import lmfit - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - -The guesses can be given as plain numbers or as ``lmfit.Parameter`` objects, as -in the case of 'sigma' above, to specify constraints. - -To integrate with the bluesky we need to provide: - -* the field with the dependent variable (in this example, ``'noisy_det'``) -* a mapping between the name(s) of independent variable(s) in - the function (``'x'``) to the corresponding field(s) in the data - (``'motor'``) -* any initial guesses expected by the model (defined above) - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.examples import motor, noisy_det - from bluesky.callbacks import LiveFit - - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - - RE(scan([noisy_det], motor, -1, 1, 100), lf) - # best-fit values for 'A', 'sigma' and 'x0' are in lf.result.values - -The fit results are accessible in the ``result`` attribute of the callback. -For example, the center of the Gaussian is ``lf.result.values['x0']``. This -could be used in a next step, like so: - -.. code-block:: python - - x0 = lf.result.values['x0'] - RE(scan([noisy_det], x0 - 1, x0 + 1, 100)) - -Refer the -`lmfit documentation `_ -for more about ``result``. - -This example uses a model with two independent variables, x and y. - -.. code-block:: python - - from bluesky.examples import motor1, motor2, det4 - - def gaussian(x, y, A, sigma, x0, y0): - return A*np.exp(-((x - x0)**2 + (y - y0)**2)/(2 * sigma**2)) - - # Specify the names of the independent variables to Model. - model = lmfit.Model(gaussian, ['x', 'y']) - - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2, - 'y0': 0.3} - - lf = LiveFit(model, 'det4', {'x': 'motor1', 'y': 'motor2'}, init_guess) - - # Scan a 2D mesh. - RE(outer_product_scan([det4], motor1, -1, 1, 20, motor2, -1, 1, 20, False), - lf) - -By default, the fit is recomputed every time a new data point is available. See -the API documentation below for other options. Fitting does not commence until -the number of accumulated data points is equal to the number of free parameters -in the model. - -.. autoclass:: bluesky.callbacks.LiveFit - -LiveFitPlot -+++++++++++ - -This is a variation on ``LivePlot`` that plots the best fit curve from -``LiveFit``. It applies to 1D model functions only. - -Repeating the example from ``LiveFit`` above, adding a plot: - -.. code-block:: python - - # same as above... - - import numpy as np - import lmfit - from bluesky.plans import scan - from bluesky.examples import motor, noisy_det - from bluesky.callbacks import LiveFit - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - - # now add the plot... - - from bluesky.callbacks import LiveFitPlot - lpf = LiveFitPlot(lf, color='r') - - RE(scan([noisy_det], motor, -1, 1, 100), lfp) - - # Notice that we did'nt need to subscribe lf directly, just lfp. - # But, as before, the results are in lf.result. - -.. plot:: - - import numpy as np - import lmfit - from bluesky.plans import scan - from bluesky.examples import motor, noisy_det - from bluesky.callbacks import LiveFit, LiveFitPlot - from bluesky import RunEngine - - RE = RunEngine({}) - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - lfp = LiveFitPlot(lf, color='r') - - RE(scan([noisy_det], motor, -1, 1, 100), lfp) - -We can use the standard ``LivePlot`` to show the data on the same axes. -Notice that they can styled independently. - -.. code-block:: python - - import matplotlib.pyplot as plt - - fig, ax = plt.subplots() # explitly create figure, axes to use below - lfp = LiveFitPlot(lf, ax=ax, color='r') - lp = LivePlot('noisy_det', 'motor', ax=ax, marker='o', linestyle='none') - - RE(scan([noisy_det], motor, -1, 1, 100), [lp, lfp]) - -.. plot:: - - import numpy as np - import lmfit - from bluesky.plans import scan - from bluesky.examples import motor, noisy_det - from bluesky.callbacks import LiveFit, LivePlot, LiveFitPlot - from bluesky import RunEngine - - RE = RunEngine({}) - - def gaussian(x, A, sigma, x0): - return A*np.exp(-(x - x0)**2/(2 * sigma**2)) - - model = lmfit.Model(gaussian) - init_guess = {'A': 2, - 'sigma': lmfit.Parameter('sigma', 3, min=0), - 'x0': -0.2} - - import matplotlib.pyplot as plt - fig, ax = plt.subplots() - lf = LiveFit(model, 'noisy_det', {'x': 'motor'}, init_guess) - lfp = LiveFitPlot(lf, ax=ax, color='r') - lp = LivePlot('noisy_det', 'motor', ax=ax, marker='o', linestyle='none') - - RE(scan([noisy_det], motor, -1, 1, 50), [lfp, lp]) - plt.draw() - -.. autoclass:: bluesky.callbacks.LiveFitPlot - -PeakStats -++++++++++ - -Compute statistics of peak-like data. Example: - -.. code-block:: python - - from bluesky.callbacks.scientific import PeakStats - from bluesky.examples import motor, det - from bluesky.plans import scan - - ps = PeakStats('motor', 'det') - RE(scan([det], motor, -5, 5, 10), ps) - -Now attributes of ``ps``, documented below, contain various peak statistics. -There is also a convenience function for plotting: - -.. code-block:: python - - from bluesky.callbacks.scientific import plot_peak_stats - - plot_peak_stats(ps) - -.. plot:: - - from bluesky import RunEngine - from bluesky.callbacks.scientific import PeakStats, plot_peak_stats - from bluesky.examples import motor, det - from bluesky.plans import scan - - RE = RunEngine({}) - ps = PeakStats('motor', 'det') - RE(scan([det], motor, -5, 5, 10), ps) - plot_peak_stats(ps) - -.. autoclass:: bluesky.callbacks.scientific.PeakStats -.. autofunction:: bluesky.callbacks.scientific.plot_peak_stats - -Callback for Export -------------------- - -Exporting Image Data as TIFF Files -++++++++++++++++++++++++++++++++++ - -First, compose a filename template. The template can include metadata or event -data from the scan. - -.. code-block:: python - - # a template that includes the scan ID and sequence number in each filename - template = "output_dir/{start[scan_id]}_{event[seq_num]}.tiff" - - # a template that sorts files into directories based user and scan ID - template = "output_dir/{start[user]}/{start[scan_id]}/{event[seq_num]}.tiff" - - # a more complex template includes actual measurements in the filenames - template = ("output_dir/{start[scan_id]}_{start[sample_name]}_" - "{event[data][temperature]}_{event[seq_num]}.tiff") - -Above, we are using a Python language feature called format strings. Notice -that inside the curly brackets we don't use quotes around the key names; it's -``{event[seq_num]}`` not ``{event['seq_num']}``. - -If each image data point is actually a stack of 2D image planes, the template -must also include ``{i}``, which will count through the image planes in the -stack. - -.. note:: - - Most metadata comes from the "start" document, hence ``start.scan_id`` - above. Review the :doc:`documents` section for details. - -Create a callback that exports TIFFs using your template. - -.. code-block:: python - - from bluesky.callbacks.broker import LiveTiffExporter - - exporter = LiveTiffExporter('image', template) - -Finally, to export all the images from a run when it finishes running, wrap the -exporter in ``post_run`` and subscribe. - -.. code-block:: python - - from bluesky.callbacks.broker import post_run - - RE.subscribe('all', post_run(exporter)) - -It also possible to write TIFFs live, hence the name ``LiveTiffExporter``, but -there is an important disadvantage to doing this subscription in the same -process: progress of the experiment may be intermittently slowed while data is -written to disk. In some circumstances, this affect on the timing of the -experiment may not be acceptable. - -.. code-block:: python - - RE.subscribe('all', exporter) - -There are more configuration options available, as given in detail below. It is -recommended to use these expensive callbacks in a separate process. - -.. autoclass:: bluesky.callbacks.broker.LiveTiffExporter - -Export All Data and Metadata in an HDF5 File -++++++++++++++++++++++++++++++++++++++++++++ - -A Stop Document is emitted at the end of every run. Subscribe to it, using it -as a cue to load the dataset via the DataBroker and export an HDF5 file -using `suitcase `_. - - -Working example: - -.. code-block:: python - - from databroker import DataBroker as db - import suitcase - - def suitcase_as_callback(name, doc): - if name != 'stop': - return - run_start_uid = doc['run_start'] - header = db[run_start_uid] - filename = '{}.h5'.format(run_start_uid) - suitcase.export(header, filename) - - RE.subscribe('stop', suitcase_as_callback) - -Export Metadata to the Olog -+++++++++++++++++++++++++++ - -The `Olog `_ ("operational log") is an -electronic logbook. We can use a callback to automatically generate log entries -at the beginning of a run. The Python interface to Olog is not straightforward, -so there is some boilerplate: - -.. code-block:: python - - from functools import partial - from pyOlog import SimpleOlogClient - from bluesky.callbacks.olog import logbook_cb_factory - - # Set up the logbook. This configures bluesky's summaries of - # data acquisition (scan type, ID, etc.). - - LOGBOOKS = ['Data Acquisition'] # list of logbook names to publish to - simple_olog_client = SimpleOlogClient() - generic_logbook_func = simple_olog_client.log - configured_logbook_func = partial(generic_logbook_func, logbooks=LOGBOOKS) - - cb = logbook_cb_factory(configured_logbook_func) - RE.subscribe('start', cb) - -The module ``bluesky.callbacks.olog`` includes some templates that format the -data from the 'start' document into a readable log entry. You can also write -customize templates and pass them to ``logbook_cb_factory``. - -.. autofunction:: bluesky.callbacks.olog.logbook_cb_factory - -Verify Data Has Been Saved --------------------------- - -The following verifies that all Documents and external files from a run have -been saved to disk and are accessible from the DataBroker. It prints a message -indicating success or failure. - -Note: If the data collection machine is not able to access the machine where -some external data is being saved, it will indicate failure. This can be a -false alarm. - -.. code-block:: python - - from bluesky.callbacks.broker import post_run, verify_files_saved - - RE.subscribe('all', post_run(verify_files_saved)) - -.. _debugging_callbacks: - -Ignoring Callback Exceptions ----------------------------- - -If an exception is raised while processing a callback, the error can interrupt -data collection. Usually, this is good: if, for example, the callback that is -saving your data encounters an error, you want to know immediately. - -But if a "flaky" callback is causing errors, it is possible to convert errors -to warnings like so. - -.. code-block:: python - - RE.ignore_callback_exceptions = False - -This is ``False`` by default. In bluesky version 0.6.4 (September 2016) and -earlier, this was ``True`` by default. - -.. _filtering: - -Filtering by Document Type --------------------------- - -There are four "subscriptions" that a callback to receive documents from: - -* 'start' -* 'stop' -* 'event' -* 'descriptor' - -Additionally, there is an 'all' subscription. - -The command: - -.. code-block:: python - - RE(plan(), cb) - -is a shorthand that is normalized to ``{'all': [cb]}``. To receive only certain -documents, specify the document routing explicitly. Examples: - -.. code-block:: python - - RE(plan(), {'start': [cb]} - RE(plan(), {'all': [cb1, cb2], 'start': [cb3]}) - -The ``subs_decorator``, presented above, accepts the same variety of inputs. - -Writing Custom Callbacks ------------------------- - -Any function that accepts a Python dictionary as its argument can be used as -a callback. Refer to simple examples above to get started. - -Two Simple Custom Callbacks -+++++++++++++++++++++++++++ - -These simple examples illustrate the concept and the usage. - -First, we define a function that takes two arguments - -#. the name of the Document type ('start', 'stop', 'event', or 'descriptor') -#. the Document itself, a dictionary - -This is the *callback*. - -.. ipython:: python - - def print_data(name, doc): - print("Measured: %s" % doc['data']) - -Then, we tell the RunEngine to call this function on each Event Document. -We are setting up a *subscription*. - -.. ipython:: python - - from bluesky.examples import det - from bluesky.plans import count - - RE(count([det]), {'event': print_data}) - -Each time the RunEngine generates a new Event Document (i.e., data point) -``print_data`` is called. - -There are five kinds of subscriptions matching the four kinds of Documents plus -an 'all' subscription that receives all Documents. - -* 'start' -* 'descriptor' -* 'event' -* 'stop' -* 'all' - -We can use the 'stop' subscription to trigger automatic end-of-run activities. -For example: - -.. code-block:: python - - def celebrate(name, doc): - # Do nothing with the input; just use it as a signal that run is over. - print("The run is finished!") - -Let's use both ``print_data`` and ``celebrate`` at once. - -.. code-block:: python - - RE(plan(), {'event': print_data, 'stop': celebrate}) - -Using multiple document types -+++++++++++++++++++++++++++++ - -Some tasks use only one Document type, but we often need to use more than one. -For example, LiveTable uses 'start' kick off the creation of a fresh table, -it uses 'event' to see the data, and it uses 'stop' to draw the bottom border. - -A convenient pattern for this kind of subscription is a class with a method -for each Document type. - -.. code-block:: python - - from bluesky.callbacks import CallbackBase - - class MyCallback(CallbackBase): - def start(self, doc): - print("I got a new 'start' Document") - # Do something - def descriptor(self, doc): - print("I got a new 'descriptor' Document") - # Do something - def event(self, doc): - print("I got a new 'event' Document") - # Do something - def stop(self, doc): - print("I got a new 'stop' Document") - # Do something - -The base class, ``CallbackBase``, takes care of dispatching each Document to -the corresponding method. If your application does not need all four, you may -simple omit methods that aren't required. - -Subscriptions in Separate Processes or Host with 0MQ ----------------------------------------------------- - -Because subscriptions are processed during a scan, it's possible that they can -slow down data collection. We mitigate this by making the subscriptions run in -a separate process. - -In the main process, where the RunEngine is executing the plan, a ``Publisher`` -is created. It subscribes to the RunEngine. It serializes the documents it -receives and it sends them over a socket to a 0MQ "forwarder device," which -rebroadcasts the documents to any number of other processes or machines on the -network. - -These other processes or machines set up a ``RemoteDispatcher`` which connects -to the "forwarder device," receives the documents, and then runs callbacks just -as they would be run if they were in the local ``RunEngine`` process. - -Multiple Publishers (each with its own RunEngine) can send documents to the -same forwarder device. RemoteDispatchers can filter the document stream based -on host, process ID, and/or ``id(RunEngine)``. - -Minimal Example -+++++++++++++++ - -Look for a forwarder device configuration file at -``/etc/zmq_forwarder_device.yml`` or -``~/.config/zmq_forwarder_device/connection.yml``. If there isn't one, create -one: - -.. code-block:: yaml - - #~/.config/zmq_forwarder_device.yml - {'frontend_port': 5577 - 'backend_port': 5578 - 'host': 'localhost'} # optional - -In production (e.g., at NSLS-II beamlines) the forwarder device should be -running in the background as a service. Here is how to start one just for play: - -.. code-block:: bash - - # uses config in /etc/zmq_forwarder_device.yml - # or ~/.config/zmq_forwarder_device/connection.yml - $ python bluesky/examples/forwarder_device.py - -Start a callback that will receive documents from the forwarder and, in this -simple example, just print them. - -.. code-block:: python - - from bluesky.callbacks.zmqsub import RemoteDispatcher - d = RemoteDispatcher('localhost', 5578) - d.subscribe('all', print) - d.start() # runs event loop forever - -On the machine/process where you want to actually collect data, -hook up a subscription to publish documents to the forwarder. Finally, -generate some documents with a simple plan. - -.. code-block:: python - - # Assume you have already create a RunEngine, RE. - - from bluesky.callbacks.zmqpub import Publisher - Publisher(RE, 'localhost', 5577) - RE([Msg('open_run'), Msg('close_run')]) - -As a result, the callback prints: - -.. code-block:: python - - start - stop - -The connection between the publisher and the subscriber is lossless. (Messages -are cached on the publisher side if the subscriber is slow.) - -Example: Plotting in separate process -+++++++++++++++++++++++++++++++++++++ - -As in the minimal example above, start a forwarder device. Then: - -On the plotting machine: - -.. code-block:: python - - import matplotlib - matplotlib.use('Qt4Agg') - - import matplotlib.pyplot as plt - plt.ion() - - from bluesky.utils import install_qt_kicker - from bluesky.callbacks import LivePlot - from bluesky.callbacks.zmqsub import RemoteDispatcher - - d = RemoteDispatcher('localhost', 5578) - install_qt_kicker(d.loop) - d.subscribe('all', LivePlot('det', 'motor')) - d.start() - -On the data collection machine, if there is not already a ``Publisher`` -running, add one. - -.. code-block:: python - - # Assume you have already create a RunEngine, RE. - - from bluesky.callbacks.zmqpub import Publisher - p = Publisher(RE, 'localhost', 5577) - -And now run a demo scan with a simulated motor and detector. - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.examples import motor, det - motor._fake_sleep = 0.5 # makes motor "move" slowly so we can watch it - RE(scan([det], motor, 1, 10, 100)) - -Publisher / RemoteDispatcher API -++++++++++++++++++++++++++++++++ - -.. autoclass:: bluesky.callbacks.zmqpub.Publisher -.. autoclass:: bluesky.callbacks.zmqsub.RemoteDispatcher diff --git a/bluesky/_sources/comparison-with-spec.rst.txt b/bluesky/_sources/comparison-with-spec.rst.txt deleted file mode 100644 index e56decadf6..0000000000 --- a/bluesky/_sources/comparison-with-spec.rst.txt +++ /dev/null @@ -1,83 +0,0 @@ -Comparison with SPEC -==================== - -`SPEC `_ is a popular software package -for instrument control and data acquisition. Many users in the synchrotron -community, from which bluesky originated, know SPEC and ask what differentiates -and motivates bluesky. Answering this question in an informed and unbiased way -is difficult, and we welcome any corrections. - -There are many good features of SPEC that have been incorporated into -bluesky, including: - -* Simple commands for common experiments, which can be used as building blocks - for more complex procedures -* Easy hardware configuration -* Interruption handling (Ctrl+C) -* Integration with EPICS (and potentially other instrument control systems) -* "Pseudomotors" presenting virtual axes -* Integration with reciprocal space transformation code - -Bluesky has also addressed certain limitations of SPEC. In fairness to SPEC, we -have the benefit of learning from its decades of use, and we are standing on -the shoulders of the modern open-source community. - -* Bluesky is free and open-source in all aspects. Macros from the SPEC user - community are open-source, but the core SPEC C source code is closed and not - free. -* Bluesky provides more control over the console output and plotting. -* SPEC was designed before large area detectors existed. Ingesting area - detector data is possible, but *ad hoc*. In bluesky, area detectors and other - higher-dimensional inputs are integrated naturally. -* SPEC writes to a custom text-based format (a "SPEC file"). Bluesky can - write---in real time or *post facto*---to any format. -* SPEC has a simulation mode. Bluesky allows users to incorporate much richer - simulation capabilities (about which more below) but, as of version 0.9.0, - provides less than SPEC out of the box. - -Using Python, a general-purpose programming language, gives several immediate -advantages: - -* Python checks syntax automatically. -* Python provides tools for interactive debugging. -* There are many more resources for learning Python. -* The language is more flexible. -* It's easy to integrate with the scientific Python ecosystem. - -Bluesky tries to go further than SPEC in some regards: - -* Complex custom procedures are easier to express. -* Automated "suspension" (pausing and resuming) is consistent and easier to - manage. -* The prevailing model in SPEC is to collect data as a step scan. Other types - of scans---such as fly scans or asynchronous monitoring---can be - done, but they are *ad hoc*. Bluesky supports several modalities of data - acquisition with equal ease. -* Bluesky can acquire multiple asynchronous, uncoordinated streams of data and - represent them in a simple :doc:`event-based data model `. -* It is easy to build tools that inspect/simulate a procedure before it is run - to check for safety, estimate time to completion, or visualize its behavior. -* Bluesky is a library that works well interactively but can also be used - programmatically in scripts or other libraries. -* Users can add arbitrary metadata with rich semantics, including large arrays - (such as masks) or nested mappings. -* Bluesky is a holistic solution for data acquisition and management. Users can - push live streaming data directly into their data processing and analysis - pipelines and/or export it into a file. - -On the other hand, one major advantage of SPEC over bluesky is its maturity. -SPEC is battle-hardened from decades of use at many facilities, and it has a -large user community. Bluesky is a young project. - -A Remark About Syntax ---------------------- - -SPEC users immediately notice that simple bluesky commands are more verbose -than their counterparts in SPEC. This is a trade-off we have made in choosing a -more expressive, general-purpose language over a single-purpose command line -interface. That "easy integration with scientific libraries" comes at the cost -of some parentheses and commas. Some of the difference is also due to the -richer abstractions required to capture the complexity of modern hardware. The -simplest commands are made less terse, but more interesting commands are made -much easier to express. Of course, users can save time by using tab-completion -and by accessing previous commands with the up arrow key. diff --git a/bluesky/_sources/cookbook/grid_in_grid.rst.txt b/bluesky/_sources/cookbook/grid_in_grid.rst.txt deleted file mode 100644 index 1e5f104da5..0000000000 --- a/bluesky/_sources/cookbook/grid_in_grid.rst.txt +++ /dev/null @@ -1,19 +0,0 @@ -Scan a grid around each sample in a grid ----------------------------------------- - -.. literalinclude:: grid_in_grid.py - -Demo output: - -.. plot:: cookbook/grid_in_grid.py - -.. ipython:: python - :suppress: - - from bluesky import RunEngine - RE = RunEngine({}) - %run -i source/cookbook/grid_in_grid.py - -.. ipython:: python - - RE(grid_in_grid(samples)) diff --git a/bluesky/_sources/cookbook/index.rst.txt b/bluesky/_sources/cookbook/index.rst.txt deleted file mode 100644 index 031a35b18c..0000000000 --- a/bluesky/_sources/cookbook/index.rst.txt +++ /dev/null @@ -1,20 +0,0 @@ -Cookbook -======== - -These are complete, working examples meant as a starting point for -customization by the user. They illustrate some of the range of what is -possible. - -For intermediate or advanced Python programmers, this section may be the right -starting point to quickly get up to speed on bluesky. For newcomers to the -language, these examples are probably not the right places to start: we -recommend at least skimming the previous sections, where the various components -of bluesky are introduced methodically and with more prose commentary. - -As you can see, this section is a work in progress. This list of examples will -grow in the coming weeks. - -.. toctree:: - - scan_gaussian - grid_in_grid diff --git a/bluesky/_sources/cookbook/index.txt b/bluesky/_sources/cookbook/index.txt deleted file mode 100644 index 36d06e99fc..0000000000 --- a/bluesky/_sources/cookbook/index.txt +++ /dev/null @@ -1,19 +0,0 @@ -Cookbook -======== - -These are complete, working examples meant as a starting point for -customization by the user. They illustrate some of the range of what is -possible. - -For intermediate or advanced Python programmers, this section may be the right -starting point to quickly get up to speed on bluesky. For newcomers to the -language, these examples are probably not the right places to start: we -recommend at least skimming the previous sections, where the various components -of bluesky are introduced methodically and with more prose commentary. - -As you can see, this section is a work in progress. This list of examples will -grow in the coming weeks. - -.. toctree:: - - scan_gaussian diff --git a/bluesky/_sources/cookbook/scan_gaussian.rst.txt b/bluesky/_sources/cookbook/scan_gaussian.rst.txt deleted file mode 100644 index a301af7d33..0000000000 --- a/bluesky/_sources/cookbook/scan_gaussian.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -Re-scan until fit achieves desired confidence ---------------------------------------------- - -.. literalinclude:: scan_gaussian.py - -.. plot:: cookbook/scan_gaussian.py diff --git a/bluesky/_sources/cookbook/scan_gaussian.txt b/bluesky/_sources/cookbook/scan_gaussian.txt deleted file mode 100644 index 41530b910c..0000000000 --- a/bluesky/_sources/cookbook/scan_gaussian.txt +++ /dev/null @@ -1,4 +0,0 @@ -Re-scan until fit achieves desired confidence ---------------------------------------------- - -.. literalinclude:: scan_gaussian.py diff --git a/bluesky/_sources/custom-plans.rst.txt b/bluesky/_sources/custom-plans.rst.txt deleted file mode 100644 index f94633a65d..0000000000 --- a/bluesky/_sources/custom-plans.rst.txt +++ /dev/null @@ -1,283 +0,0 @@ -Messages -======== - -The built-in plans are heavily customizable and can satisfy many applications. Most users can find everything they need in :doc:`plans`. - -This section explores Messages, the granular instructions that make up a plan, -in depth. - - -A message is comprised of: - -* a command string, such as 'read', 'set', or 'pause' -* a target object, such as ``motor``, if applicable -* positional arguments -* keyword arguments - - -Examples: - -.. code-block:: python - - from bluesky import Msg - from bluesky.examples import motor - - Msg('read', motor) - Msg('set', motor, 5) - -The ``Msg`` object itself is a namedtuple. - -Below, we build up a collection of example plans demonstrating a variety of -different commands and use cases. - -Simplest Scan -------------- - -Messages are passed to the RunEngine through a Python *generator* (more on -these below). Here is a very simple scan that sets a motor's position to 5 -and reads the position back. - -.. code-block:: python - - def simple_scan(det, motor): - yield Msg('set', motor, 5) - yield Msg('read', motor) - -The RunEngine processes these messages like so: - -.. code-block:: python - - motor.set(5) - motor.read() - -To read from a detector, we also need the 'trigger' command. - -.. code-block:: python - - def simple_scan(det, motor): - yield Msg('set', motor, 5) - yield Msg('read', motor) - yield Msg('trigger', det) - yield Msg('read', det) - -Making Scans Responsive ------------------------ - -Two-way communication is possible between the generator and the RunEngine. -For example, the 'read' command responds with its reading. We can use it to -make an on-the-fly decision about whether to continue or stop. - -.. code-block:: python - - def conditional_break(det, motor, threshold): - """Set, trigger, read until the detector reads intensity < threshold""" - i = 0 - while True: - print("LOOP %d" % i) - yield Msg('set', motor, i) - yield Msg('trigger', det) - reading = yield Msg('read', det) - if reading['det']['value'] < threshold: - print('DONE') - break - i += 1 - -The response from 'read' -- ``reading``, above -- is formatted like: - -.. code-block:: python - - {: {'value': , 'timestamp': }, ...} - -For a detailed technical description of the messages and their responses, -see :doc:`msg`. - -Sleeping --------- - -Sleeping is as simple as it sounds. It might be used, for example, to add -extra delay to allow a sample to equilibrate to the temperature set by a -temperature controller. - -.. code-block:: python - - def sleepy(det, motor): - "Set, trigger motor, sleep for a fixed time, trigger detector, read" - yield Msg('set', motor, 5) - yield Msg('sleep', None, 2) # units: seconds - yield Msg('trigger', det) - yield Msg('read', det) - -Notice that unlike 'set', 'read', and 'trigger', the 'sleep' command does -not have a target object. We use ``None`` as a placeholder. - -Waiting -------- - -Use the 'wait' command to block progress until an object report that it is -ready. For example, wait for a motor to finish moving. - -First, give the 'set' command a ``block_group`` -keyword argument. This is just a label that we can use to refer to it later. -Then, use 'wait' to tell the RunEngine to block progress until everything in -that ``block_group`` reports that it is ready. - -.. code-block:: python - - def wait_one(det, motor): - "Set, trigger, read" - yield Msg('set', motor, 5, block_group='A') # Add to group 'A'. - yield Msg('wait', None, 'A') # Wait for everything in group 'A'. - yield Msg('trigger', det) - yield Msg('read', det) - -By assigning multiple objects to the same ``block_group``, you can wait until -the last one reports it is ready. - -.. code-block:: python - - def wait_multiple(det, motors): - "Set motors, trigger all motors, wait for all motors to move." - for motor in motors: - yield Msg('set', motor, 5, block_group='A') - # Wait for everything in group 'A' to report done. - yield Msg('wait', None, 'A') - yield Msg('trigger', det) - yield Msg('read', det) - -If the above seems unnecessarily complex, here is the payoff. By using -different ``block_group`` labels, you can wait for different groups at -different points in the scan. - -.. code-block:: python - - def wait_complex(det, motors): - "Set motors, trigger motors, wait for all motors to move in groups." - # Same as above... - for motor in motors[:-1]: - yield Msg('set', motor, 5, block_group='A') - # ...but put the last motor is separate group. - yield Msg('set', motors[-1], 5, block_group='B') - # Wait for everything in group 'A' to report done. - yield Msg('wait', None, 'A') - yield Msg('trigger', det) - yield Msg('read', det) - # Wait for everything in group 'B' to report done. - yield Msg('wait', None, 'B') - yield Msg('trigger', det) - yield Msg('read', det) - -Pauseable Scans ---------------- - -The 'pause' command pauses the RunEngine. Details of pausing and resuming were -addressed :doc:`previously `. - -The 'checkpoint' command defines where a scan can be safely resumed after an -interruption. - -.. code-block:: python - - def conditional_pause(det, motor, defer): - for i in range(5): - yield Msg('checkpoint') - yield Msg('set', motor, i) - yield Msg('trigger', det) - reading = yield Msg('read', det) - if reading['det']['value'] < 0.2: - yield Msg('pause', defer=defer) - yield Msg('set', motor, i + 0.5) - -If detector reading dips below 0.2, the scan is paused. - -The next example is a step scan that pauses after each data point is collected. -(This is the function we used in the -:ref:`first pausing example `.) - - -.. code-block:: python - - def cautious_stepscan(det, motor): - for i in range(-5, 5): - yield Msg('checkpoint') - yield Msg('create') - yield Msg('set', motor, i) - yield Msg('trigger', det) - ret_m = yield Msg('read', motor) - ret_d = yield Msg('read', det) - yield Msg('save') - print("Value at {m} is {d}. Pausing.".format( - m=ret_m[motor.name]['value'], d=ret_d[det1.name]['value'])) - yield Msg('pause', None, hard=False) - -The 'create' and 'save' commands bundle and save the readings between them, as -described just below. Notice that 'checkpoint' occurs before 'create'. It is -illegal to place checkpoints inside a create--save pair. - -Creating Documents (Saving the Data) ------------------------------------- - -Data is bundled into *Events*, logical groupings of measurements that can be -considered "simultaneous" for practical purposes. (Individual measurement -times are recorded, but they are usually ignored.) When readings are -bundled as an Event, an Event Document is created and made available to -:doc:`subscriptions `. - -To bundle data into an Event, use the 'create' and 'save' commands. Any -'read' commands that occur between the two will be bundled into an Event. - -.. code-block:: python - - def simple_scan_saving(motor, det): - "Set, trigger, read" - yield Msg('open_run') - yield Msg('create') - yield Msg('set', motor, 5) - yield Msg('read', motor) - yield Msg('trigger', det) - yield Msg('read', det) - yield Msg('save') - yield Msg('close_run') - -The above generates one Event. By looping through several create--save pairs, -we can generate many Events. - -.. code-block:: python - - def stepscan(motor, det): - yield Msg('open_run') - for i in range(-5, 5): - yield Msg('create') - yield Msg('set', motor, i) - yield Msg('trigger', det) - yield Msg('read', motor) - yield Msg('read', det) - yield Msg('save') - yield Msg('close_run') - -Fly Scans ---------- - -From the point of view of bluesky, a "fly scan" is any object that needs to -be told to start and then, some time later, to return its data in bulk with -no supervision in between. These two steps are called "kickoff" and "collect" -respectively. - -.. code-block:: python - - def flyscan(flyer): - Msg('kickoff', flyer) - # some time later... - Msg('collect', flyer) - -Obviously, all of the interesting action is up to ``flyer`` -- but that is -the point. - - -Registering Custom Commands ---------------------------- - -The RunEngine can be taught any new commands. They can be registered using the -following methods. - -.. automethod:: bluesky.run_engine.RunEngine.register_command -.. automethod:: bluesky.run_engine.RunEngine.unregister_command diff --git a/bluesky/_sources/custom-plans.txt b/bluesky/_sources/custom-plans.txt deleted file mode 100644 index f94633a65d..0000000000 --- a/bluesky/_sources/custom-plans.txt +++ /dev/null @@ -1,283 +0,0 @@ -Messages -======== - -The built-in plans are heavily customizable and can satisfy many applications. Most users can find everything they need in :doc:`plans`. - -This section explores Messages, the granular instructions that make up a plan, -in depth. - - -A message is comprised of: - -* a command string, such as 'read', 'set', or 'pause' -* a target object, such as ``motor``, if applicable -* positional arguments -* keyword arguments - - -Examples: - -.. code-block:: python - - from bluesky import Msg - from bluesky.examples import motor - - Msg('read', motor) - Msg('set', motor, 5) - -The ``Msg`` object itself is a namedtuple. - -Below, we build up a collection of example plans demonstrating a variety of -different commands and use cases. - -Simplest Scan -------------- - -Messages are passed to the RunEngine through a Python *generator* (more on -these below). Here is a very simple scan that sets a motor's position to 5 -and reads the position back. - -.. code-block:: python - - def simple_scan(det, motor): - yield Msg('set', motor, 5) - yield Msg('read', motor) - -The RunEngine processes these messages like so: - -.. code-block:: python - - motor.set(5) - motor.read() - -To read from a detector, we also need the 'trigger' command. - -.. code-block:: python - - def simple_scan(det, motor): - yield Msg('set', motor, 5) - yield Msg('read', motor) - yield Msg('trigger', det) - yield Msg('read', det) - -Making Scans Responsive ------------------------ - -Two-way communication is possible between the generator and the RunEngine. -For example, the 'read' command responds with its reading. We can use it to -make an on-the-fly decision about whether to continue or stop. - -.. code-block:: python - - def conditional_break(det, motor, threshold): - """Set, trigger, read until the detector reads intensity < threshold""" - i = 0 - while True: - print("LOOP %d" % i) - yield Msg('set', motor, i) - yield Msg('trigger', det) - reading = yield Msg('read', det) - if reading['det']['value'] < threshold: - print('DONE') - break - i += 1 - -The response from 'read' -- ``reading``, above -- is formatted like: - -.. code-block:: python - - {: {'value': , 'timestamp': }, ...} - -For a detailed technical description of the messages and their responses, -see :doc:`msg`. - -Sleeping --------- - -Sleeping is as simple as it sounds. It might be used, for example, to add -extra delay to allow a sample to equilibrate to the temperature set by a -temperature controller. - -.. code-block:: python - - def sleepy(det, motor): - "Set, trigger motor, sleep for a fixed time, trigger detector, read" - yield Msg('set', motor, 5) - yield Msg('sleep', None, 2) # units: seconds - yield Msg('trigger', det) - yield Msg('read', det) - -Notice that unlike 'set', 'read', and 'trigger', the 'sleep' command does -not have a target object. We use ``None`` as a placeholder. - -Waiting -------- - -Use the 'wait' command to block progress until an object report that it is -ready. For example, wait for a motor to finish moving. - -First, give the 'set' command a ``block_group`` -keyword argument. This is just a label that we can use to refer to it later. -Then, use 'wait' to tell the RunEngine to block progress until everything in -that ``block_group`` reports that it is ready. - -.. code-block:: python - - def wait_one(det, motor): - "Set, trigger, read" - yield Msg('set', motor, 5, block_group='A') # Add to group 'A'. - yield Msg('wait', None, 'A') # Wait for everything in group 'A'. - yield Msg('trigger', det) - yield Msg('read', det) - -By assigning multiple objects to the same ``block_group``, you can wait until -the last one reports it is ready. - -.. code-block:: python - - def wait_multiple(det, motors): - "Set motors, trigger all motors, wait for all motors to move." - for motor in motors: - yield Msg('set', motor, 5, block_group='A') - # Wait for everything in group 'A' to report done. - yield Msg('wait', None, 'A') - yield Msg('trigger', det) - yield Msg('read', det) - -If the above seems unnecessarily complex, here is the payoff. By using -different ``block_group`` labels, you can wait for different groups at -different points in the scan. - -.. code-block:: python - - def wait_complex(det, motors): - "Set motors, trigger motors, wait for all motors to move in groups." - # Same as above... - for motor in motors[:-1]: - yield Msg('set', motor, 5, block_group='A') - # ...but put the last motor is separate group. - yield Msg('set', motors[-1], 5, block_group='B') - # Wait for everything in group 'A' to report done. - yield Msg('wait', None, 'A') - yield Msg('trigger', det) - yield Msg('read', det) - # Wait for everything in group 'B' to report done. - yield Msg('wait', None, 'B') - yield Msg('trigger', det) - yield Msg('read', det) - -Pauseable Scans ---------------- - -The 'pause' command pauses the RunEngine. Details of pausing and resuming were -addressed :doc:`previously `. - -The 'checkpoint' command defines where a scan can be safely resumed after an -interruption. - -.. code-block:: python - - def conditional_pause(det, motor, defer): - for i in range(5): - yield Msg('checkpoint') - yield Msg('set', motor, i) - yield Msg('trigger', det) - reading = yield Msg('read', det) - if reading['det']['value'] < 0.2: - yield Msg('pause', defer=defer) - yield Msg('set', motor, i + 0.5) - -If detector reading dips below 0.2, the scan is paused. - -The next example is a step scan that pauses after each data point is collected. -(This is the function we used in the -:ref:`first pausing example `.) - - -.. code-block:: python - - def cautious_stepscan(det, motor): - for i in range(-5, 5): - yield Msg('checkpoint') - yield Msg('create') - yield Msg('set', motor, i) - yield Msg('trigger', det) - ret_m = yield Msg('read', motor) - ret_d = yield Msg('read', det) - yield Msg('save') - print("Value at {m} is {d}. Pausing.".format( - m=ret_m[motor.name]['value'], d=ret_d[det1.name]['value'])) - yield Msg('pause', None, hard=False) - -The 'create' and 'save' commands bundle and save the readings between them, as -described just below. Notice that 'checkpoint' occurs before 'create'. It is -illegal to place checkpoints inside a create--save pair. - -Creating Documents (Saving the Data) ------------------------------------- - -Data is bundled into *Events*, logical groupings of measurements that can be -considered "simultaneous" for practical purposes. (Individual measurement -times are recorded, but they are usually ignored.) When readings are -bundled as an Event, an Event Document is created and made available to -:doc:`subscriptions `. - -To bundle data into an Event, use the 'create' and 'save' commands. Any -'read' commands that occur between the two will be bundled into an Event. - -.. code-block:: python - - def simple_scan_saving(motor, det): - "Set, trigger, read" - yield Msg('open_run') - yield Msg('create') - yield Msg('set', motor, 5) - yield Msg('read', motor) - yield Msg('trigger', det) - yield Msg('read', det) - yield Msg('save') - yield Msg('close_run') - -The above generates one Event. By looping through several create--save pairs, -we can generate many Events. - -.. code-block:: python - - def stepscan(motor, det): - yield Msg('open_run') - for i in range(-5, 5): - yield Msg('create') - yield Msg('set', motor, i) - yield Msg('trigger', det) - yield Msg('read', motor) - yield Msg('read', det) - yield Msg('save') - yield Msg('close_run') - -Fly Scans ---------- - -From the point of view of bluesky, a "fly scan" is any object that needs to -be told to start and then, some time later, to return its data in bulk with -no supervision in between. These two steps are called "kickoff" and "collect" -respectively. - -.. code-block:: python - - def flyscan(flyer): - Msg('kickoff', flyer) - # some time later... - Msg('collect', flyer) - -Obviously, all of the interesting action is up to ``flyer`` -- but that is -the point. - - -Registering Custom Commands ---------------------------- - -The RunEngine can be taught any new commands. They can be registered using the -following methods. - -.. automethod:: bluesky.run_engine.RunEngine.register_command -.. automethod:: bluesky.run_engine.RunEngine.unregister_command diff --git a/bluesky/_sources/debugging.rst.txt b/bluesky/_sources/debugging.rst.txt deleted file mode 100644 index ebbc3b9466..0000000000 --- a/bluesky/_sources/debugging.rst.txt +++ /dev/null @@ -1,191 +0,0 @@ -********************* -Debugging and Logging -********************* - -.. versionchanged:: 1.6.0 - - Bluesky's use of Python's logging framework has been completely reworked to - follow Python's documented best practices for libraries. - -Bluesky uses Python's logging framework, which enables sophisticated log -management. For common simple cases, including viewing logs in the terminal or -writing them to a file, the next section illustrates streamlined, -copy/paste-able examples. Users who are familiar with that framework or who -need to route logs to multiple destinations may wish to skip ahead to -:ref:`logger_api`. - -Useful Snippets -=============== - -Log warnings ------------- - -This is the recommended standard setup. - -.. code-block:: python - - from bluesky import config_bluesky_logging - config_bluesky_logging() - -It will display ``'bluesky'`` log records of ``WARNING`` level or higher in the -terminal (standard out) with a format tailored to bluesky. - -Maximum verbosity ------------------ - -If the RunEngine is "hanging," running slowly, or repeatedly encountering an -error, it is useful to know exactly where in the plan the problem is occurring. -To follow the RunEngine's progress through the plan, crank up the verbosity of -the logging. - -This will display each message from the plan just before the RunEngine -processes it, giving a clear indication of when plan execution is stuck. - -.. code-block:: python - - from bluesky import config_bluesky_logging - config_bluesky_logging(level='DEBUG') - -Log to a file -------------- - -This will direct all log messages to a file instead of the terminal (standard -out). - -.. code-block:: python - - from bluesky import config_bluesky_logging - config_bluesky_logging(file='/tmp/bluesky.log', level='DEBUG') - -.. important:: - - We strongly recommend setting levels on *handlers* not on *loggers*. - In previous versions of bluesky, we recommended adjusting the level on the - *logger*, as in ``RE.log.setLevel('DEBUG')``. We now recommended - that you *avoid* setting levels on loggers because it would affect all - handlers downstream, potentially inhibiting some other part of the program - from collecting the records it wants to collect. - -.. _logger_api: - -Bluesky's Logging-Related API -============================= - -Logger Names ------------- - -Here are the primary loggers used by bluesky. - -* ``'bluesky'`` --- the logger to which all bluesky log records propagate -* ``'bluesky.emit_document'`` --- A log record is emitted whenever a Document - is emitted. The log record does not contain the full content of the - Document. -* ``'bluesky.RE'`` --- Records from a RunEngine. INFO-level notes state - changes. DEBUG-level notes when each message from a plan is about to be - processed and when a status object has completed. -* ``'bluesky.RE.msg`` --- A log record is emitted when each - :class:`~bluesky.utils.Msg` is about to be processed. -* ``'bluesky.RE.state`` --- A log record is emitted when the RunEngine's state - changes. - -There are also some module-level loggers for specific features. - -Formatter ---------- - -.. autoclass:: bluesky.log.LogFormatter - -Global Handler ---------------- - -Following Python's recommendation, bluesky does not install any handlers at -import time, but it provides a function to set up a basic useful configuration -in one line, similar to Python's :py:func:`logging.basicConfig` but with some -additional options---and scoped to the ``'bluesky'`` logger with bluesky's -:class:`bluesky.log.LogFormatter`. It streamlines common use cases without -interfering with more sophisticated use cases. - -We recommend that facilities using bluesky leave this function for users and -configure any standardized, facility-managed logging handlers separately, as -described in the next section. - -.. autofunction:: bluesky.log.config_bluesky_logging -.. autofunction:: bluesky.log.get_handler - -Advanced Example -================ - -The flow of log event information in loggers and handlers is illustrated in the -following diagram: - -.. image:: https://docs.python.org/3/_images/logging_flow.png - -For further reference, see the Python 3 logging howto: -https://docs.python.org/3/howto/logging.html#logging-flow - -As an illustrative example, we will set up two handlers using the Python -logging framework directly, ignoring bluesky's convenience function. - -Suppose we set up a handler aimed at a file: - -.. code-block:: python - - import logging - file_handler = logging.FileHandler('bluesky.log') - -And another aimed at `Logstash `_: - -.. code-block:: python - - import logstash # requires python-logstash package - logstash_handler = logstash.TCPLogstashHandler(, , version=1) - -We can attach the handlers to the bluesky logger, to which all log records -created by bluesky propagate: - -.. code-block:: python - - logger = logging.getLogger('bluesky') - logger.addHandler(logstash_handler) - logger.addHandler(file_filter) - -We can set the verbosity of each handler. Suppose want maximum verbosity in the -file but only medium verbosity in logstash. - -.. code-block:: python - - logstash_handler.setLevel('INFO') - file_handler.setLevel('DEBUG') - -Finally, ensure that "effective level" of ``logger`` is at least as verbose as -the most verbose handler---in this case, ``'DEBUG'``. By default, at import, -its level is not set - -.. ipython:: python - :verbatim: - - logging.getLevelName(logger.level) - 'NOTSET' - -and so it inherits the level of Python's default -"handler of last resort," :py:obj:`logging.lastResort`, which is ``'WARNING'``. - -.. ipython:: python - :verbatim: - - logging.getLevelName(logger.getEffectiveLevel()) - 'WARNING' - -In this case we should set it to ``'DEBUG'``, to match the most verbose level -of the handler we have added. - -.. code-block:: python - - logger.setLevel('DEBUG') - -This makes DEBUG-level records *available* to all handlers. Our logstash -handler, set to ``'INFO'``, will filter out DEBUG-level records. - -To globally disable the generation of any log records at or below a certain -verbosity, which may be helpful for optimizing performance, Python provides -:py:func:`logging.disable`. diff --git a/bluesky/_sources/debugging.txt b/bluesky/_sources/debugging.txt deleted file mode 100644 index 11ef48f14c..0000000000 --- a/bluesky/_sources/debugging.txt +++ /dev/null @@ -1,117 +0,0 @@ -Debugging and Logging -===================== - -Message Hook ------------- - -If the RunEngine is "hanging," running slowly, or repeatedly encountering an -error, it is useful to know exactly where in the plan the problem is occurring. -To follow the RunEngine's progress through the plan, use the message hook: - -.. code-block:: python - - RE.msg_hook = print - -Before each message ``msg`` in the plan is processed by the RunEngine, -``print(msg)`` will be called. The result is *extremely* verbose and may even -significantly slow down plan execution, so it should only be used for -debugging. - -Using ``print`` is easiest, but in general any function can be used. For -example, to write to a file: - -.. code-block:: python - - def append_to_file(msg): - with open('myfile.log', 'a') as f: - f.write(str(msg)) - - RE.msg_hook = append_to_file - -To restore default behavior, set the hook back to ``None``: - -.. code-block:: python - - RE.msg_hook = None - -State Hook ----------- - -The RunEngine can be in one of three states: - -* 'idle' (ready to accept a new plan) -* 'running' (running the event loop and processing a plan) -* 'paused' (not running the event loop, but holding onto state in preparation - for possibly resuming) - -The state is exposed through the RunEngine's ``state`` attribute. To monitor -changes in state, use the ``state_hook`` attribute. Like ``msg_hook`` above, it -can be set to ``None`` (default) or a function. In this case, the function -should accept two arguments: the new state and the previous state. - -Logging -------- - -The RunEngine integrates with Python's built-in logging framework. It provides -a convenient attribute for configuring logging quickly. - -.. code-block:: python - - # standard Python logging setup - import logging - logging.basicConfig() - - RE.log.disabled = False - -With this configuration, executing a plan prints log messages to the screen. - -The logger issues INFO-level messages whenever the RunEngine changes state -(idle -> running, running -> paused, etc.) and DEBUG-level messages whenever a -new Document is created and emitted to the subscriptions. Demo: - -.. code-block:: python - - In [3]: RE(count([det])) - Out[3]: ['f015945c-7e9f-4d2c-9a83-d1db1b31fb43'] - - In [4]: RE.verbose = True - - In [5]: RE(count([det])) - INFO:bluesky.run_engine_id4371931376:Change state on - from 'idle' -> - 'running' - DEBUG:bluesky.run_engine_id4371931376:Starting new with uid - '4f3e173f-3383-49a4-94bc-cac571144c4d' - DEBUG:bluesky.run_engine_id4371931376:Emitted RunStart - (uid='4f3e173f-3383-49a4-94bc-cac571144c4d') - DEBUG:bluesky.run_engine_id4371931376:The object reader: det reports - trigger is done with status True. - DEBUG:bluesky.run_engine_id4371931376:Emitted Event Descriptor with name - 'primary' containing data keys dict_keys(['det']) - (uid='400f6d4a-db5d-454b-9b1c-5e759eb8511b') - DEBUG:bluesky.run_engine_id4371931376:Emitted Event with data keys - dict_keys(['det']) (uid='dd2dedba-4ac7-4761-a94a-2e65c1579aa8') - DEBUG:bluesky.run_engine_id4371931376:Stopping run - '4f3e173f-3383-49a4-94bc-cac571144c4d' - DEBUG:bluesky.run_engine_id4371931376:Emitted RunStop - (uid='654f4bfb-043f-4b81-9a8f-371ce276caf3') - INFO:bluesky.run_engine_id4371931376:Change state on - from 'running' -> - 'idle' - Out[5]: ['4f3e173f-3383-49a4-94bc-cac571144c4d'] - -The log messages include the Python id of the RunEngine instance (``id(RE)``) -in case logs from multiple instances end up in the same file. - -The ``RE.log`` attribute is a standard Python logger object. For example, to -change the log level to skip DEBUG-level messages: - -.. code-block:: python - - RE.log.setLevel(logging.INFO) - -.. note:: - - For back-compatibility with old versions of bluesky, there is also an - ``RE.verbose`` attribute. ``RE.verbose`` is a synonym for - ``not RE.log.disabled``. diff --git a/bluesky/_sources/documents.rst.txt b/bluesky/_sources/documents.rst.txt deleted file mode 100644 index fb38abe345..0000000000 --- a/bluesky/_sources/documents.rst.txt +++ /dev/null @@ -1,179 +0,0 @@ -.. currentmodule:: bluesky.plans - -Documents -========= - -A primary design goal of bluesky is to enable better research by recording -rich metadata alongside measured data for use in later analysis. Documents are -how we do this. - -A *document* is our term for a Python dictionary with a schema --- that is, -organized in a -`formally specified `_ way --- created -by the RunEngine during plan execution. All of the metadata and data generated -by executing the plan is organized into documents. - -A :doc:`later section ` describes how outside functions can -"subscribe" to a stream of these documents, visualizing, processing, or saving -them. This section provides an outline of documents themselves, aiming to give -a sense of the structure and familiarity with useful components. - -.. _run_overview: - -Overview of a "Run" -------------------- - -Each document belongs to a *run* --- loosely speaking, a dataset. Executing any -of the :ref:`built-in pre-assembled plans `, like -:func:`scan` and :func:`count`, creates one run. - -.. note:: - - Fundamentally, the scope of a run is intentionally vague and flexible. One - plan might generate many runs or one long run. It just depends on how you - want to organize your data, both at collection time and analysis time. - - The tutorial's :ref:`tutorial_capture_data` section explores this. - -The documents in each run are: - -- A **Run Start document**, containg all of the metadata known at the start of - the run. Highlights: - - - time --- the start time - - plan_name --- e.g., ``'scan'`` or ``'count'`` - - uid --- unique ID that identifies this run - - scan_id --- human-friendly integer scan ID (not necessarily unique) - - any other :doc:`metadata captured at execution time ` from the - plan or the user - -- **Event documents**, containing the actual measurements. These are your data. - - - time --- a timestamp for this group of readings - - seq_num --- sequence number, counting up from 1 - - data --- a dictionary of readings like - ``{'temperature': 5.0, 'position': 3.0}`` - - timestamps --- a dictionary of individual timestamps for each reading, - from the hardware - -- **Event Descriptor documents** provide a schema for the data in the Event - documents. They list all of the keys in the Event's data and give useful - information about them, such as units and precision. They also contain - information about the configuration of the hardware. - -- A **Run Stop document**, containing metadata known only at the end of the - run. Highlights: - - - time --- the time when the run was completed - - exit_status --- "success", "abort", or "fail" - -Every document has a ``time`` (its creation time) and a separate ``uid`` to -identify it. The Event documents also have a ``descriptor`` field linking them -to the Event Descriptor with their metadata. And the Event Descriptor and -Run Stop documents have a ``run_start`` field linking them to their Run -Start. Thus, all the documents in a run are linked back to the Run Start. - -Documents in Detail -------------------- - -Run Start -+++++++++ - -Again, a 'start' document marks the beginning of the run. It comprises -everything we know before we start taking data, including all metadata provided -by the user and the plan. (More on this in the :doc:`next section `.) - -All built-in plans provide some useful metadata like the names of the -detector(s) and motor(s) used. (User-defined plans may also do this; see -:ref:`this section ` of the tutorial.) - -The command: - -.. code-block:: python - - from bluesky.plans import scan - from ophyd.sim import det, motor # simulated detector, motor - - # Scan 'motor' from -3 to 3 in 10 steps, taking readings from 'det'. - RE(scan([det], motor, -3, 3, 16), purpose='calibration', - sample='kryptonite') - -generates a 'start' document like this: - -.. code-block:: python - - # 'start' document - {'purpose': 'calibration', - 'sample': 'kryptonite', - 'detectors': ['det'], - 'motors': ['motor'], - 'plan_name': 'scan', - 'plan_type': 'generator', - 'plan_args': {'detectors': '[det]', - 'motor': 'Mover(...)', - 'num': '16', - 'start': '-3', - 'stop': '3'}, - 'scan_id': 282, - 'time': 1442521005.6099606, - 'uid': '', - } - -.. note:: - - Time is given in UNIX time (seconds since 1970). Software for looking at - the data would, of course, translate that into a more human-readable form. - -Event -+++++ - -An 'event' records one or more measurements with an associated time. - -.. code-block:: python - - # 'event' document - {'data': - {'temperature': 5.0, - 'x_setpoint': 3.0, - 'x_readback': 3.05}, - 'timestamps': - {'temperature': 1442521007.9258342, - 'x_setpoint': 1442521007.5029348, - 'x_readback': 1442521007.5029348}, - 'time': 1442521007.3438923, - 'seq_num': 1 - 'uid': '', - 'descriptor': ''} - -From a data analysis perspective, these readings were simultaneous, but in -actuality the occurred at separate times. The separate times of the individual -readings are not thrown away (they are recorded in 'timestamps') but the -overall event 'time' is often more useful. - -Run Stop -++++++++ - -A 'stop' document marks the end of the run. It contains metadata that is not -known until the run completes. - -The most commonly useful fields here are 'time' and 'exit_status'. - -.. code-block:: python - - # 'stop' document - {'exit_status': 'success', # or 'fail' or 'abort' - 'reason': '', # The RunEngine can provide reason for failure here. - 'time': 1442521012.1021606, - 'uid': '', - 'start': '', - 'num_events': {'primary': 16} - } - -Event Descriptor -++++++++++++++++ - -As stated above, a 'descriptor' document provides a schema for the data in the -Event documents. It provides useful information about each key in the data and -about the configuration of the hardware. The layout of a descriptor is detailed -and takes some time to cover, so we defer it to a -:doc:`later section `. diff --git a/bluesky/_sources/documents.txt b/bluesky/_sources/documents.txt deleted file mode 100644 index bcce305d14..0000000000 --- a/bluesky/_sources/documents.txt +++ /dev/null @@ -1,178 +0,0 @@ -.. currentmodule:: bluesky.plans - -Documents -========= - -A primary design goal of bluesky is to enable better research by recording -rich metadata alongside measured data for use in later analysis. Documents are -how we do this. - -A *document* is our term for a Python dictionary with a schema --- that is, -organized in a -`formally specified `_ way --- created -by the RunEngine during plan execution. All of the metadata and data generated -by executing the plan is organized into documents. - -A :doc:`later section ` describes how outside functions can -"subscribe" to a stream of these documents, visualizing, processing, or saving -them. This section provides an outline of documents themselves, aiming to give -a sense of the structure and familiarity with useful components. - -.. _run_overview: - -Overview of a "Run" -------------------- - -Each document belongs to a *run* --- loosely speaking, a dataset. Executing any -of the :ref:`built-in pre-assembled plans `, like -:func:`scan` and :func:`count`, creates one run. - -.. note:: - - Fundamentally, the scope of a run is intentionally vague and flexible. One - plan might generate many runs or one long run. It just depends on how you - want to organize your data, both at collection time and analysis time. - - The section :ref:`reimplementing_count` explores this. - -The documents in each run are: - -- A **Run Start document**, containg all of the metadata known at the start of - the run. Highlights: - - - time --- the start time - - plan_name --- e.g., ``'scan'`` or ``'count'`` - - uid --- unique ID that identifies this run - - scan_id --- human-friendly integer scan ID (not necessarily unique) - - any other :doc:`metadata captured at execution time ` from the - plan or the user - -- **Event documents**, containing the actual measurements. These are your data. - - - time --- a timestamp for this group of readings - - seq_num --- sequence number, counting up from 1 - - data --- a dictionary of readings like - ``{'temperature': 5.0, 'position': 3.0}`` - - timestamps --- a dictionary of individual timestamps for each reading, - from the hardware - -- **Event Descriptor documents** provide a schema for the data in the Event - documents. They list all of the keys in the Event's data and give useful - information about them, such as units and precision. They also contain - information about the configuration of the hardware. - -- A **Run Stop document**, containing metadata known only at the end of the - run. Highlights: - - - time --- the time when the run was completed - - exit_status --- "success", "abort", or "fail" - -Every document has a ``time`` (its creation time) and a separate ``uid`` to -identify it. The Event documents also have a ``descriptor`` field linking them -to the Event Descriptor with their metadata. And the Event Descriptor and -Run Stop documents have a ``run_start`` field linking them to their Run -Start. Thus, all the documents in a run are linked back to the Run Start. - -Documents in Detail -------------------- - -Run Start -+++++++++ - -Again, a 'start' document marks the beginning of the run. It comprises -everything we know before we start taking data, including all metadata provided -by the user and the plan. (More on this in the :doc:`next section `.) - -All built-in plans provide some useful metadata like the names of the -detector(s) and motor(s) used. (User-definied plans may also do this; see -:ref:`this section `.) - -The command: - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.examples import det, motor # simulated detector, motor - - # Scan 'motor' from -3 to 3 in 10 steps, taking readings from 'det'. - RE(scan([det], motor, -3, 3, 16), purpose='calibration', - sample='kryptonite') - -generates a 'start' document like this: - -.. code-block:: python - - # 'start' document - {'purpose': 'calibration', - 'sample': 'kryptonite', - 'detectors': ['det'], - 'motors': ['motor'], - 'plan_name': 'scan', - 'plan_type': 'generator', - 'plan_args': {'detectors': '[det]', - 'motor': 'Mover(...)', - 'num': '16', - 'start': '-3', - 'stop': '3'}, - 'scan_id': 282, - 'time': 1442521005.6099606, - 'uid': '', - } - -.. note:: - - Time is given in UNIX time (seconds since 1970). Software for looking at - the data would, of course, translate that into a more human-readable form. - -Event -+++++ - -An 'event' records one or more measurements with an associated time. - -.. code-block:: python - - # 'event' document - {'data': - {'temperature': 5.0, - 'x_setpoint': 3.0, - 'x_readback': 3.05}, - 'timestamps': - {'temperature': 1442521007.9258342, - 'x_setpoint': 1442521007.5029348, - 'x_readback': 1442521007.5029348}, - 'time': 1442521007.3438923, - 'seq_num': 1 - 'uid': '', - 'descriptor': ''} - -From a data analysis perspective, these readings were simultaneous, but in -actuality the occurred at separate times. The separate times of the individual -readings are not thrown away (they are recorded in 'timestamps') but the -overall event 'time' is often more useful. - -Run Stop -++++++++ - -A 'stop' document marks the end of the run. It contains metadata that is not -known until the run completes. - -The most commonly useful fields here are 'time' and 'exit_status'. - -.. code-block:: python - - # 'stop' document - {'exit_status': 'success', # or 'fail' or 'abort' - 'reason': '', # The RunEngine can provide reason for failure here. - 'time': 1442521012.1021606, - 'uid': '', - 'start': '' - } - -Event Descriptor -++++++++++++++++ - -As stated above, a 'descriptor' document provides a schema for the data in the -Event documents. It provides useful information about each key in the data and -about the configuration of the hardware. The layout of a descriptor is detailed -and takes some time to cover, so we defer it to a -:doc:`later section `. diff --git a/bluesky/_sources/event_descriptors.rst.txt b/bluesky/_sources/event_descriptors.rst.txt deleted file mode 100644 index acd80c2538..0000000000 --- a/bluesky/_sources/event_descriptors.rst.txt +++ /dev/null @@ -1,210 +0,0 @@ -Event Descriptors -================= - -In the section on :doc:`documents`, we gave an overview of the four kinds of -document. We presented an example Run Start, Event, and Run Stop, but we -deferred detailed discussion of the Event Descriptor. - -Recall our example 'event' document. - -.. code-block:: python - - # 'event' document (same as above, shown again for reference) - {'data': - {'temperature': 5.0, - 'x_setpoint': 3.0, - 'x_readback': 3.05}, - 'timestamps': - {'temperature': 1442521007.9258342, - 'x_setpoint': 1442521007.5029348, - 'x_readback': 1442521007.5029348}, - 'time': 1442521007.3438923, - 'seq_num': 1, - 'uid': '', - 'descriptor': ''} - -Typically, an experiment generates multiple event documents with the same data -keys. For example, there might be ten sequential readings, generating ten event -documents like the one above --- with different readings and timestamps but -identical data keys. All these events refer back to a 'descriptor' with -metadata about the data keys and the configuration of the devices involved. - -.. note:: - - We got the term "data keys" from ``event['data'].keys()``. Again, in our - example, the data keys are ``['temperature', 'x_setpoint', 'x_readback']`` - -Data Keys ---------- - -First, the descriptor provides metadata about each data key. - -* dtype --- 'number', 'string', 'array', or 'object' (dict) -* shape --- ``None`` or a list of dimensions like ``[5, 5]`` for a 5x5 array -* source --- a description of the hardware that uniquely identifies it, such as - an EPICS Process Variable -* (optional) external --- a string specifying where external data, such as a - large image array, is stored - -Arbitrary additional fields are allowed, such as precision or units. -The RunEngine obtains this information from each device it sees by calling -``device.describe()``. - -.. code-block:: python - - # excerpt of a 'descriptor' document - {'data_keys': - {'temperature': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'K', - 'precision': 3}, - 'x_setpoint': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}, - 'x_readback': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}, - ...} - -Object Keys ------------ - -The ``object_keys`` provide an association between each device and its data keys. - -This is needed because a given device can produce multiple data keys. For -example, suppose the ``x_readback`` and ``x_setpoint`` data keys in our example -came from the same device, a motor named ``'x'``. - -.. code-block:: python - - # excerpt of a 'descriptor' document - {'object_keys': - {'x': ['x_setpoint', 'x_readback'], - 'temp_ctrl': ['temperature']}, - ...} - -Specifically, it maps ``device.name`` to ``list(device.describe())``. - -Configuration -------------- - -Complex devices often have many parameters that do not need to be read anew -with every data point. They are "configuration," by which we mean they don't -typically change in the middle of a run. A detector's exposure time is usually -(but not always) in this category. - -Devices delineate between the two by providing two different methods that the -RunEngine can call: ``device.read()`` returns normals readings that are *not* -considered configuration; ``device.read_configuration()`` returns the readings -that are considered configuration. - -The first time during a run that the RunEngine is told to read a device, it -reads the device's configuration also. The return value of -``device.describe_configuration()`` is recorded in -``configuration[device.name]['data_keys']``. The return value of -``device.read_configuration()`` is collated into -``configuration[device.name]['data']`` and -``configuration[device.name]['timestamps']``. - -In this example, ``x`` has one configuration data key, and ``temp_ctrl`` -happens to provide no configuration information. - -.. code-block:: python - - # excerpt of a 'descriptor' document - {'configuration': - {'x': - {'data': {'offset': 0.1}, - 'timestamps': {'offset': 1442521007.534918}, - 'data_keys': - {'offset': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}}, - 'temp_ctrl': - {'data': {}, - 'timestamps': {} - 'data_keys': {}}} - ...} - -Hints ------ - -This is an experimental feature. Devices can provide information via a -``hints`` attribute that is stored here. See :ref:`hints`. - -.. code-block:: python - - # excerpt of a 'descriptor' document - {'hints': - {'x' {'fields': ['x_readback']}, - 'temp_ctrl': {'fields': ['temperature']}} - ...} - - -Complete Sample ---------------- - -Taken together, our example 'descriptor' document looks like this. - -.. code-block:: python - - # complete 'descriptor' document - {'data_keys': - {'temperature': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'K', - 'precision': 3}, - 'x_setpoint': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}, - 'x_readback': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}, - - 'object_keys': - {'x': ['x_setpoint', 'x_readback'], - 'temp_ctrl': ['temperature']}, - - 'configuration': - {'x': - {'data': {'offset': 0.1}, - 'timestamps': {'offset': 1442521007.534918}, - 'data_keys': - {'offset': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2} - 'temp_ctrl': - {'data': {}, - 'timestamps': {} - 'data_keys': {}}} - } - - 'hints': - {'x' {'fields': ['x_readback']}, - 'temp_ctrl': {'fields': ['temperature']}} - - 'time': 1442521007.3438923, - 'uid': '', - 'run_start': ''} diff --git a/bluesky/_sources/event_descriptors.txt b/bluesky/_sources/event_descriptors.txt deleted file mode 100644 index e2d5320411..0000000000 --- a/bluesky/_sources/event_descriptors.txt +++ /dev/null @@ -1,192 +0,0 @@ -Event Descriptors -================= - -In the section on :doc:`documents`, we gave an overview of the four kinds of -document. We presented an example Run Start, Event, and Run Stop, but we -deferred detailed discussion of the Event Descriptior. - -Recall our example 'event' document. - -.. code-block:: python - - # 'event' document (same as above, shown again for reference) - {'data': - {'temperature': 5.0, - 'x_setpoint': 3.0, - 'x_readback': 3.05}, - 'timestamps': - {'temperature': 1442521007.9258342, - 'x_setpoint': 1442521007.5029348, - 'x_readback': 1442521007.5029348}, - 'time': 1442521007.3438923, - 'seq_num': 1, - 'uid': '', - 'descriptor': ''} - -Typically, an experiment generates multiple event documents with the same data -keys. For example, there might be ten sequential readings, generating ten event -documents like the one above --- with different readings and timestamps but -identical data keys. All these events refer back to a 'descriptor' with -metadata about the data keys and the configuration of the devices involved. - -.. note:: - - We got the term "data keys" from ``event['data'].keys()``. Again, in our - example, the data keys are ``['temperature', 'x_setpoint', 'x_readback']`` - -Data Keys ---------- - -First, the descriptor provides metadata about each data key. - -* dtype --- 'number', 'string', 'array', or 'object' (dict) -* shape --- ``None`` or a list of dimensions like ``[5, 5]`` for a 5x5 array -* source --- a description of the hardware that uniquely identifies it, such as - an EPICS Process Variable -* (optional) external --- a string specifying where external data, such as a - large image array, is stored - -Arbitrary additional fields are allowed, such as precision or units. -The RunEngine obtains this information from each device it sees by calling -``device.describe()``. - -.. code-block:: python - - # excerpt of a 'descriptor' document - {'data_keys': - {'temperature': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'K', - 'precision': 3}, - 'x_setpoint': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}, - 'x_readback': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}, - ...} - -Object Keys ------------ - -The ``object_keys`` provide an association between each device and its data keys. - -This is needed because a given device can produce multiple data keys. For -example, suppose the ``x_readback`` and ``x_setpoint`` data keys in our example -came from the same device, a motor named ``'x'``. - -.. code-block:: python - - # excerpt of a 'descriptor' document - {'object_keys': - {'x': ['x_setpoint', 'x_readback'], - 'temp_ctrl': ['temperature']}, - ...} - -Specifically, it maps ``device.name`` to ``list(device.describe())``. - -Configuration -------------- - -Complex devices often have many parameters that do not need to be read anew -with every data point. They are "configuration," by which we mean they don't -typically change in the middle of a run. A detector's exposure time is usually -(but not always) in this category. - -Devices delineate between the two by providing two different methods that the -RunEngine can call: ``device.read()`` returns normals readings that are *not* -considered configuration; ``device.read_configuration()`` returns the readings -that are considered configuration. - -The first time during a run that the RunEngine is told to read a device, it -reads the device's configuration also. The return value of -``device.describe_configuration()`` is recorded in -``configuration[device.name]['data_keys']``. The return value of -``device.read_configuration()`` is collated into -``configuration[device.name]['data']`` and -``configuration[device.name]['timestamps']``. - -In this example, ``x`` has one configuration data key, and ``temp_ctrl`` -happens to provide no configuration information. - -.. code-block:: python - - # excerpt of a 'descriptor' document - {'configuration': - {'x': - {'data': {'offset': 0.1}, - 'timestamps': {'offset': 1442521007.534918}, - 'data_keys': - {'offset': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}}, - 'temp_ctrl': - {'data': {}, - 'timestamps': {} - 'data_keys': {}}} - ...} - -Complete Sample ---------------- - -Taken together, our example 'descriptor' document looks like this. - -.. code-block:: python - - # complete 'descriptor' document - {'data_keys': - {'temperature': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'K', - 'precision': 3}, - 'x_setpoint': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}, - 'x_readback': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2}}, - - 'object_keys': - {'x': ['x_setpoint', 'x_readback'], - 'temp_ctrl': ['temperature']}, - - 'configuration': - {'x': - {'data': {'offset': 0.1}, - 'timestamps': {'offset': 1442521007.534918}, - 'data_keys': - {'offset': - {'dtype': 'number', - 'source': '', - 'shape': [], - 'units': 'mm', - 'precision': 2} - 'temp_ctrl': - {'data': {}, - 'timestamps': {} - 'data_keys': {}}} - } - - - 'time': 1442521007.3438923, - 'uid': '', - 'run_start': ''} diff --git a/bluesky/_sources/from-pyepics-to-bluesky.rst.txt b/bluesky/_sources/from-pyepics-to-bluesky.rst.txt deleted file mode 100644 index f2ee6d5be2..0000000000 --- a/bluesky/_sources/from-pyepics-to-bluesky.rst.txt +++ /dev/null @@ -1,22 +0,0 @@ -=============================================== -Translating Direct PyEpics Code to Bluesky Code -=============================================== - -.. warning: - - This section is still a work in progress. - -How? -==== - -=========================== ====================================== -interactive (blocking) re-write for BlueSky plan() -=========================== ====================================== -some.device.put("config") yield from mv(some.device, "config") -motor.move(52) yield from mv(motor, 52) -motor.velocity.put(5) yield from mv(motor.velocity, 5) -=========================== ====================================== - - -Why? -==== diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.backstop_collect.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.backstop_collect.rst.txt deleted file mode 100644 index 024efb881d..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.backstop_collect.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.backstop\_collect -============================================= - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.backstop_collect \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_checkpoint.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_checkpoint.rst.txt deleted file mode 100644 index 8641ae0dec..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_checkpoint.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.clear\_checkpoint -============================================= - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.clear_checkpoint \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_monitors.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_monitors.rst.txt deleted file mode 100644 index b38c5386e3..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.clear_monitors.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.clear\_monitors -=========================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.clear_monitors \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.close_run.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.close_run.rst.txt deleted file mode 100644 index 8134379a87..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.close_run.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.close\_run -====================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.close_run \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.collect.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.collect.rst.txt deleted file mode 100644 index 5e6909e978..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.collect.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.collect -=================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.collect \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.complete.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.complete.rst.txt deleted file mode 100644 index 4f3d186165..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.complete.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.complete -==================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.complete \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.configure.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.configure.rst.txt deleted file mode 100644 index d6034a99b7..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.configure.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.configure -===================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.configure \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.create.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.create.rst.txt deleted file mode 100644 index bf56b3dfe7..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.create.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.create -================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.create \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.drop.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.drop.rst.txt deleted file mode 100644 index ee1f584f2b..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.drop.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.drop -================================ - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.drop \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.kickoff.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.kickoff.rst.txt deleted file mode 100644 index 0ffa52326c..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.kickoff.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.kickoff -=================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.kickoff \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.monitor.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.monitor.rst.txt deleted file mode 100644 index 54cdb40649..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.monitor.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.monitor -=================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.monitor \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.open_run.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.open_run.rst.txt deleted file mode 100644 index 9b71bda409..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.open_run.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.open\_run -===================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.open_run \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.read.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.read.rst.txt deleted file mode 100644 index 6d3af66f70..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.read.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.read -================================ - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.read \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.record_interruption.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.record_interruption.rst.txt deleted file mode 100644 index fe49bf7dc5..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.record_interruption.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.record\_interruption -================================================ - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.record_interruption \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state.rst.txt deleted file mode 100644 index edcdddadf2..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.reset\_checkpoint\_state -==================================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.reset_checkpoint_state \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state_coro.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state_coro.rst.txt deleted file mode 100644 index f8d8c6b070..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.reset_checkpoint_state_coro.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.reset\_checkpoint\_state\_coro -========================================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.reset_checkpoint_state_coro \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.restore_monitors.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.restore_monitors.rst.txt deleted file mode 100644 index 6e38de164e..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.restore_monitors.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.restore\_monitors -============================================= - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.restore_monitors \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.rewind.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.rewind.rst.txt deleted file mode 100644 index e2e8710591..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.rewind.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.rewind -================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.rewind \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.rst.txt deleted file mode 100644 index 5a91aae9bf..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.rst.txt +++ /dev/null @@ -1,43 +0,0 @@ -bluesky.bundlers.RunBundler -=========================== - -.. currentmodule:: bluesky.bundlers - -.. autoclass:: RunBundler - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RunBundler.__init__ - ~RunBundler.backstop_collect - ~RunBundler.clear_checkpoint - ~RunBundler.clear_monitors - ~RunBundler.close_run - ~RunBundler.collect - ~RunBundler.complete - ~RunBundler.configure - ~RunBundler.create - ~RunBundler.drop - ~RunBundler.kickoff - ~RunBundler.monitor - ~RunBundler.open_run - ~RunBundler.read - ~RunBundler.record_interruption - ~RunBundler.reset_checkpoint_state - ~RunBundler.reset_checkpoint_state_coro - ~RunBundler.restore_monitors - ~RunBundler.rewind - ~RunBundler.save - ~RunBundler.suspend_monitors - ~RunBundler.unmonitor - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.save.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.save.rst.txt deleted file mode 100644 index 878c50bd78..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.save.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.save -================================ - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.save \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.suspend_monitors.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.suspend_monitors.rst.txt deleted file mode 100644 index 1cbf5f5462..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.suspend_monitors.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.suspend\_monitors -============================================= - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.suspend_monitors \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.unmonitor.rst.txt b/bluesky/_sources/generated/bluesky.bundlers.RunBundler.unmonitor.rst.txt deleted file mode 100644 index c854a2c9f6..0000000000 --- a/bluesky/_sources/generated/bluesky.bundlers.RunBundler.unmonitor.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.bundlers.RunBundler.unmonitor -===================================== - -.. currentmodule:: bluesky.bundlers - -.. automethod:: RunBundler.unmonitor \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_baseline.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_baseline.rst.txt deleted file mode 100644 index a257323ac1..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_baseline.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.disable\_baseline -=================================================================== - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.disable_baseline \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_heading.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_heading.rst.txt deleted file mode 100644 index bc0522efaf..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_heading.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.disable\_heading -================================================================== - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.disable_heading \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_plots.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_plots.rst.txt deleted file mode 100644 index 5addd3640c..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_plots.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.disable\_plots -================================================================ - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.disable_plots \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_table.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_table.rst.txt deleted file mode 100644 index e8af2c48a2..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.disable_table.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.disable\_table -================================================================ - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.disable_table \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_baseline.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_baseline.rst.txt deleted file mode 100644 index 7816b45da6..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_baseline.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.enable\_baseline -================================================================== - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.enable_baseline \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_heading.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_heading.rst.txt deleted file mode 100644 index 9c5b43ed05..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_heading.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.enable\_heading -================================================================= - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.enable_heading \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_plots.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_plots.rst.txt deleted file mode 100644 index 6e6d664976..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_plots.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.enable\_plots -=============================================================== - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.enable_plots \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_table.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_table.rst.txt deleted file mode 100644 index 33f15b6499..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.enable_table.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback.enable\_table -=============================================================== - -.. currentmodule:: bluesky.callbacks.best_effort - -.. automethod:: BestEffortCallback.enable_table \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.rst.txt b/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.rst.txt deleted file mode 100644 index e5b745a09e..0000000000 --- a/bluesky/_sources/generated/bluesky.callbacks.best_effort.BestEffortCallback.rst.txt +++ /dev/null @@ -1,49 +0,0 @@ -bluesky.callbacks.best\_effort.BestEffortCallback -================================================= - -.. currentmodule:: bluesky.callbacks.best_effort - -.. autoclass:: BestEffortCallback - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~BestEffortCallback.__init__ - ~BestEffortCallback.bulk_datum - ~BestEffortCallback.bulk_events - ~BestEffortCallback.clear - ~BestEffortCallback.datum - ~BestEffortCallback.datum_page - ~BestEffortCallback.descriptor - ~BestEffortCallback.disable_baseline - ~BestEffortCallback.disable_heading - ~BestEffortCallback.disable_plots - ~BestEffortCallback.disable_table - ~BestEffortCallback.emit - ~BestEffortCallback.enable_baseline - ~BestEffortCallback.enable_heading - ~BestEffortCallback.enable_plots - ~BestEffortCallback.enable_table - ~BestEffortCallback.event - ~BestEffortCallback.event_page - ~BestEffortCallback.plot_prune_fifo - ~BestEffortCallback.resource - ~BestEffortCallback.start - ~BestEffortCallback.stop - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~BestEffortCallback.log - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.abs_set.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.abs_set.rst.txt deleted file mode 100644 index be4c783488..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.abs_set.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.abs\_set -============================ - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: abs_set \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.broadcast_msg.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.broadcast_msg.rst.txt deleted file mode 100644 index aebaa2a865..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.broadcast_msg.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.broadcast\_msg -================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: broadcast_msg \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.caching_repeater.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.caching_repeater.rst.txt deleted file mode 100644 index 00b8c63c9e..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.caching_repeater.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.caching\_repeater -===================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: caching_repeater \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.checkpoint.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.checkpoint.rst.txt deleted file mode 100644 index 2106cc5d74..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.checkpoint.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.checkpoint -============================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: checkpoint \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.clear_checkpoint.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.clear_checkpoint.rst.txt deleted file mode 100644 index b162f6e84b..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.clear_checkpoint.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.clear\_checkpoint -===================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: clear_checkpoint \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.close_run.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.close_run.rst.txt deleted file mode 100644 index 1c4909530c..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.close_run.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.close\_run -============================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: close_run \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.collect.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.collect.rst.txt deleted file mode 100644 index 0ac29012dd..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.collect.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.collect -=========================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: collect \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.complete.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.complete.rst.txt deleted file mode 100644 index 99cc11abd9..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.complete.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.complete -============================ - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: complete \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.configure.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.configure.rst.txt deleted file mode 100644 index 9ff00d3698..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.configure.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.configure -============================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: configure \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.create.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.create.rst.txt deleted file mode 100644 index f670d280b9..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.create.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.create -========================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: create \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.deferred_pause.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.deferred_pause.rst.txt deleted file mode 100644 index 3b49d3b25f..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.deferred_pause.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.deferred\_pause -=================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: deferred_pause \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.drop.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.drop.rst.txt deleted file mode 100644 index 505955f977..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.drop.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.drop -======================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: drop \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.input_plan.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.input_plan.rst.txt deleted file mode 100644 index 88a723d07c..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.input_plan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.input\_plan -=============================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: input_plan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.install_suspender.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.install_suspender.rst.txt deleted file mode 100644 index 50c2c7165c..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.install_suspender.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.install\_suspender -====================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: install_suspender \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.kickoff.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.kickoff.rst.txt deleted file mode 100644 index 56a7146a18..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.kickoff.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.kickoff -=========================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: kickoff \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.monitor.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.monitor.rst.txt deleted file mode 100644 index 8e17675a61..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.monitor.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.monitor -=========================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: monitor \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.move_per_step.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.move_per_step.rst.txt deleted file mode 100644 index bffc5a7ff8..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.move_per_step.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.move\_per\_step -=================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: move_per_step \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.mv.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.mv.rst.txt deleted file mode 100644 index 5ae956afa6..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.mv.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.mv -====================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: mv \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.mvr.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.mvr.rst.txt deleted file mode 100644 index c38eff5e8d..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.mvr.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.mvr -======================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: mvr \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.null.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.null.rst.txt deleted file mode 100644 index 7bef96aede..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.null.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.null -======================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: null \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.one_1d_step.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.one_1d_step.rst.txt deleted file mode 100644 index 072af1a81c..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.one_1d_step.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.one\_1d\_step -================================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: one_1d_step \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.one_nd_step.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.one_nd_step.rst.txt deleted file mode 100644 index 33e759f159..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.one_nd_step.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.one\_nd\_step -================================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: one_nd_step \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.one_shot.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.one_shot.rst.txt deleted file mode 100644 index 4789a72d44..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.one_shot.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.one\_shot -============================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: one_shot \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.open_run.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.open_run.rst.txt deleted file mode 100644 index 5eba2c1b95..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.open_run.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.open\_run -============================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: open_run \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.pause.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.pause.rst.txt deleted file mode 100644 index f132a637e3..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.pause.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.pause -========================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: pause \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.rd.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.rd.rst.txt deleted file mode 100644 index 7f2fb0790e..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.rd.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.rd -====================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: rd \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.read.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.read.rst.txt deleted file mode 100644 index e6bbfb2748..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.read.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.read -======================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: read \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.rel_set.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.rel_set.rst.txt deleted file mode 100644 index b518e313c9..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.rel_set.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.rel\_set -============================ - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: rel_set \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.remove_suspender.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.remove_suspender.rst.txt deleted file mode 100644 index 5dadc8f971..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.remove_suspender.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.remove\_suspender -===================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: remove_suspender \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.repeat.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.repeat.rst.txt deleted file mode 100644 index 6c70cec62f..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.repeat.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.repeat -========================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: repeat \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.repeater.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.repeater.rst.txt deleted file mode 100644 index 7bf96020d9..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.repeater.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.repeater -============================ - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: repeater \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.save.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.save.rst.txt deleted file mode 100644 index 462e2cec9b..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.save.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.save -======================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: save \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.sleep.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.sleep.rst.txt deleted file mode 100644 index 763c2ad950..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.sleep.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.sleep -========================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: sleep \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.stage.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.stage.rst.txt deleted file mode 100644 index f838eccddc..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.stage.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.stage -========================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: stage \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.stop.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.stop.rst.txt deleted file mode 100644 index 7ec435b0c8..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.stop.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.stop -======================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: stop \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.subscribe.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.subscribe.rst.txt deleted file mode 100644 index 88f2028957..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.subscribe.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.subscribe -============================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: subscribe \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.trigger.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.trigger.rst.txt deleted file mode 100644 index 366f0dff9f..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.trigger.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.trigger -=========================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: trigger \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.trigger_and_read.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.trigger_and_read.rst.txt deleted file mode 100644 index cea0abe68a..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.trigger_and_read.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.trigger\_and\_read -====================================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: trigger_and_read \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.unmonitor.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.unmonitor.rst.txt deleted file mode 100644 index a072ebc910..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.unmonitor.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.unmonitor -============================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: unmonitor \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.unstage.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.unstage.rst.txt deleted file mode 100644 index d4ca86f0ba..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.unstage.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.unstage -=========================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: unstage \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.unsubscribe.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.unsubscribe.rst.txt deleted file mode 100644 index cf25187368..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.unsubscribe.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.unsubscribe -=============================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: unsubscribe \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.wait.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.wait.rst.txt deleted file mode 100644 index 0a546dfa81..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.wait.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.wait -======================== - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: wait \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plan_stubs.wait_for.rst.txt b/bluesky/_sources/generated/bluesky.plan_stubs.wait_for.rst.txt deleted file mode 100644 index ba0f017361..0000000000 --- a/bluesky/_sources/generated/bluesky.plan_stubs.wait_for.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plan\_stubs.wait\_for -============================= - -.. currentmodule:: bluesky.plan_stubs - -.. autofunction:: wait_for \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.adaptive_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.adaptive_scan.rst.txt deleted file mode 100644 index 3a1e62ad87..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.adaptive_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.adaptive\_scan -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: adaptive_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.count.rst.txt b/bluesky/_sources/generated/bluesky.plans.count.rst.txt deleted file mode 100644 index b15cf99768..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.count.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.count -=================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: count \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.fly.rst.txt b/bluesky/_sources/generated/bluesky.plans.fly.rst.txt deleted file mode 100644 index 7cec0b9e62..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.fly.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.fly -================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: fly \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.grid_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.grid_scan.rst.txt deleted file mode 100644 index b8dcc37ecc..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.grid_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.grid\_scan -======================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: grid_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.list_grid_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.list_grid_scan.rst.txt deleted file mode 100644 index f39b68570b..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.list_grid_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.list\_grid\_scan -============================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: list_grid_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.list_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.list_scan.rst.txt deleted file mode 100644 index b2084e18c8..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.list_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.list\_scan -======================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: list_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.log_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.log_scan.rst.txt deleted file mode 100644 index 50e895188a..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.log_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.log\_scan -======================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: log_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.ramp_plan.rst.txt b/bluesky/_sources/generated/bluesky.plans.ramp_plan.rst.txt deleted file mode 100644 index 4d721616e1..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.ramp_plan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.ramp\_plan -======================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: ramp_plan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_adaptive_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_adaptive_scan.rst.txt deleted file mode 100644 index 821d1413c5..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_adaptive_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_adaptive\_scan -================================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_adaptive_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_grid_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_grid_scan.rst.txt deleted file mode 100644 index b57bdb482d..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_grid_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_grid\_scan -============================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_grid_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_list_grid_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_list_grid_scan.rst.txt deleted file mode 100644 index 85e8c5ae86..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_list_grid_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_list\_grid\_scan -=================================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_list_grid_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_list_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_list_scan.rst.txt deleted file mode 100644 index b5ca577907..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_list_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_list\_scan -============================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_list_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_log_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_log_scan.rst.txt deleted file mode 100644 index b5d04ded29..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_log_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_log\_scan -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_log_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_scan.rst.txt deleted file mode 100644 index 0a93c87a46..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_scan -======================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_spiral.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_spiral.rst.txt deleted file mode 100644 index 9b4be5391f..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_spiral.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_spiral -========================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_spiral \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_spiral_fermat.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_spiral_fermat.rst.txt deleted file mode 100644 index 6ed4d2fa0c..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_spiral_fermat.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_spiral\_fermat -================================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_spiral_fermat \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.rel_spiral_square.rst.txt b/bluesky/_sources/generated/bluesky.plans.rel_spiral_square.rst.txt deleted file mode 100644 index 086ca62e45..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.rel_spiral_square.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.rel\_spiral\_square -================================= - -.. currentmodule:: bluesky.plans - -.. autofunction:: rel_spiral_square \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.scan.rst.txt b/bluesky/_sources/generated/bluesky.plans.scan.rst.txt deleted file mode 100644 index 9746c0130b..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.scan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.scan -================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: scan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.scan_nd.rst.txt b/bluesky/_sources/generated/bluesky.plans.scan_nd.rst.txt deleted file mode 100644 index 1bb18ce1ac..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.scan_nd.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.scan\_nd -====================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: scan_nd \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.spiral.rst.txt b/bluesky/_sources/generated/bluesky.plans.spiral.rst.txt deleted file mode 100644 index d351bd4f78..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.spiral.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.spiral -==================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: spiral \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.spiral_fermat.rst.txt b/bluesky/_sources/generated/bluesky.plans.spiral_fermat.rst.txt deleted file mode 100644 index 1e39a4a248..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.spiral_fermat.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.spiral\_fermat -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: spiral_fermat \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.spiral_square.rst.txt b/bluesky/_sources/generated/bluesky.plans.spiral_square.rst.txt deleted file mode 100644 index bf49094342..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.spiral_square.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.spiral\_square -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: spiral_square \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.tune_centroid.rst.txt b/bluesky/_sources/generated/bluesky.plans.tune_centroid.rst.txt deleted file mode 100644 index 13d36977af..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.tune_centroid.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.tune\_centroid -============================ - -.. currentmodule:: bluesky.plans - -.. autofunction:: tune_centroid \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.plans.tweak.rst.txt b/bluesky/_sources/generated/bluesky.plans.tweak.rst.txt deleted file mode 100644 index b17566d1a2..0000000000 --- a/bluesky/_sources/generated/bluesky.plans.tweak.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.plans.tweak -=================== - -.. currentmodule:: bluesky.plans - -.. autofunction:: tweak \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.baseline_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.baseline_decorator.rst.txt deleted file mode 100644 index 9185712888..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.baseline_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.baseline\_decorator -========================================= - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: baseline_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.baseline_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.baseline_wrapper.rst.txt deleted file mode 100644 index aedc43c0a4..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.baseline_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.baseline\_wrapper -======================================= - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: baseline_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.contingency_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.contingency_wrapper.rst.txt deleted file mode 100644 index 34a689d327..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.contingency_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.contingency\_wrapper -========================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: contingency_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.finalize_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.finalize_decorator.rst.txt deleted file mode 100644 index 69d86751a5..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.finalize_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.finalize\_decorator -========================================= - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: finalize_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.finalize_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.finalize_wrapper.rst.txt deleted file mode 100644 index c87c1007d8..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.finalize_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.finalize\_wrapper -======================================= - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: finalize_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.fly_during_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.fly_during_decorator.rst.txt deleted file mode 100644 index 382e8fa6fe..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.fly_during_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.fly\_during\_decorator -============================================ - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: fly_during_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.fly_during_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.fly_during_wrapper.rst.txt deleted file mode 100644 index 30aa8a0d44..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.fly_during_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.fly\_during\_wrapper -========================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: fly_during_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.inject_md_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.inject_md_decorator.rst.txt deleted file mode 100644 index 42856c3f99..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.inject_md_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.inject\_md\_decorator -=========================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: inject_md_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.inject_md_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.inject_md_wrapper.rst.txt deleted file mode 100644 index 066da46ce8..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.inject_md_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.inject\_md\_wrapper -========================================= - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: inject_md_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_decorator.rst.txt deleted file mode 100644 index 5cf500fe2b..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.lazily\_stage\_decorator -============================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: lazily_stage_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_wrapper.rst.txt deleted file mode 100644 index e665488776..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.lazily_stage_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.lazily\_stage\_wrapper -============================================ - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: lazily_stage_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.make_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.make_decorator.rst.txt deleted file mode 100644 index 88a2ae9833..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.make_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.make\_decorator -===================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: make_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.monitor_during_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.monitor_during_decorator.rst.txt deleted file mode 100644 index a1b2da8f64..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.monitor_during_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.monitor\_during\_decorator -================================================ - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: monitor_during_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.monitor_during_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.monitor_during_wrapper.rst.txt deleted file mode 100644 index 4fd48d1d8c..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.monitor_during_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.monitor\_during\_wrapper -============================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: monitor_during_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.msg_mutator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.msg_mutator.rst.txt deleted file mode 100644 index 8cff4298a3..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.msg_mutator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.msg\_mutator -================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: msg_mutator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.pchain.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.pchain.rst.txt deleted file mode 100644 index aa013fd69e..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.pchain.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.pchain -============================ - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: pchain \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.plan_mutator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.plan_mutator.rst.txt deleted file mode 100644 index c1d8979930..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.plan_mutator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.plan\_mutator -=================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: plan_mutator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.relative_set_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.relative_set_decorator.rst.txt deleted file mode 100644 index ce6823b323..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.relative_set_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.relative\_set\_decorator -============================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: relative_set_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.relative_set_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.relative_set_wrapper.rst.txt deleted file mode 100644 index 7390a14011..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.relative_set_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.relative\_set\_wrapper -============================================ - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: relative_set_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.reset_positions_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.reset_positions_decorator.rst.txt deleted file mode 100644 index 0ef5d9c738..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.reset_positions_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.reset\_positions\_decorator -================================================= - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: reset_positions_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.reset_positions_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.reset_positions_wrapper.rst.txt deleted file mode 100644 index 2839df4ec0..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.reset_positions_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.reset\_positions\_wrapper -=============================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: reset_positions_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.run_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.run_decorator.rst.txt deleted file mode 100644 index 310b8b07c3..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.run_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.run\_decorator -==================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: run_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.run_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.run_wrapper.rst.txt deleted file mode 100644 index ed8b2af5f9..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.run_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.run\_wrapper -================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: run_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.single_gen.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.single_gen.rst.txt deleted file mode 100644 index 99b9457425..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.single_gen.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.single\_gen -================================= - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: single_gen \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.stage_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.stage_decorator.rst.txt deleted file mode 100644 index 41d0e5602c..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.stage_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.stage\_decorator -====================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: stage_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.stage_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.stage_wrapper.rst.txt deleted file mode 100644 index e8977150e3..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.stage_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.stage\_wrapper -==================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: stage_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.subs_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.subs_decorator.rst.txt deleted file mode 100644 index b76a267725..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.subs_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.subs\_decorator -===================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: subs_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.subs_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.subs_wrapper.rst.txt deleted file mode 100644 index 879fa9053b..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.subs_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.subs\_wrapper -=================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: subs_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.suspend_decorator.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.suspend_decorator.rst.txt deleted file mode 100644 index 5b84d9ec29..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.suspend_decorator.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.suspend\_decorator -======================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: suspend_decorator \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.preprocessors.suspend_wrapper.rst.txt b/bluesky/_sources/generated/bluesky.preprocessors.suspend_wrapper.rst.txt deleted file mode 100644 index 68cc553aab..0000000000 --- a/bluesky/_sources/generated/bluesky.preprocessors.suspend_wrapper.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.preprocessors.suspend\_wrapper -====================================== - -.. currentmodule:: bluesky.preprocessors - -.. autofunction:: suspend_wrapper \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.process.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.process.rst.txt deleted file mode 100644 index 69ef4a49cb..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.process.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.Dispatcher.process -====================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: Dispatcher.process \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.rst.txt deleted file mode 100644 index b451b046e1..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.rst.txt +++ /dev/null @@ -1,32 +0,0 @@ -bluesky.run\_engine.Dispatcher -============================== - -.. currentmodule:: bluesky.run_engine - -.. autoclass:: Dispatcher - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Dispatcher.__init__ - ~Dispatcher.process - ~Dispatcher.subscribe - ~Dispatcher.unsubscribe - ~Dispatcher.unsubscribe_all - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~Dispatcher.ignore_exceptions - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.subscribe.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.subscribe.rst.txt deleted file mode 100644 index f0fd554fb0..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.subscribe.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.Dispatcher.subscribe -======================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: Dispatcher.subscribe \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe.rst.txt deleted file mode 100644 index fbf9526214..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.Dispatcher.unsubscribe -========================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: Dispatcher.unsubscribe \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe_all.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe_all.rst.txt deleted file mode 100644 index cfc13dc2d5..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.Dispatcher.unsubscribe_all.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.Dispatcher.unsubscribe\_all -=============================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: Dispatcher.unsubscribe_all \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.__call__.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.__call__.rst.txt deleted file mode 100644 index 0359fc5d04..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.__call__.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.\_\_call\_\_ -========================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.__call__ \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.abort.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.abort.rst.txt deleted file mode 100644 index b0f7cf8440..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.abort.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.abort -=================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.abort \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.clear_suspenders.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.clear_suspenders.rst.txt deleted file mode 100644 index 17463fd486..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.clear_suspenders.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.clear\_suspenders -=============================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.clear_suspenders \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.commands.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.commands.rst.txt deleted file mode 100644 index 73296131a5..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.commands.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.commands -====================================== - -.. currentmodule:: bluesky.run_engine - -.. autoproperty:: RunEngine.commands \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.halt.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.halt.rst.txt deleted file mode 100644 index 0a72a1f70c..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.halt.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.halt -================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.halt \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.install_suspender.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.install_suspender.rst.txt deleted file mode 100644 index 2bff79c64c..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.install_suspender.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.install\_suspender -================================================ - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.install_suspender \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.print_command_registry.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.print_command_registry.rst.txt deleted file mode 100644 index dd4b9dd0ab..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.print_command_registry.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.print\_command\_registry -====================================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.print_command_registry \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.register_command.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.register_command.rst.txt deleted file mode 100644 index 021a6b238f..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.register_command.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.register\_command -=============================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.register_command \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.remove_suspender.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.remove_suspender.rst.txt deleted file mode 100644 index 9cd1a5e4ca..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.remove_suspender.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.remove\_suspender -=============================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.remove_suspender \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_pause.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_pause.rst.txt deleted file mode 100644 index 5ba0e78670..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_pause.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.request\_pause -============================================ - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.request_pause \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_suspend.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_suspend.rst.txt deleted file mode 100644 index 4274361cca..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.request_suspend.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.request\_suspend -============================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.request_suspend \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.resume.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.resume.rst.txt deleted file mode 100644 index fb7ec35eb1..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.resume.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.resume -==================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.resume \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.rst.txt deleted file mode 100644 index 0c49a0e70d..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.rst.txt +++ /dev/null @@ -1,52 +0,0 @@ -bluesky.run\_engine.RunEngine -============================= - -.. currentmodule:: bluesky.run_engine - -.. autoclass:: RunEngine - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~RunEngine.__init__ - ~RunEngine.abort - ~RunEngine.clear_suspenders - ~RunEngine.emit - ~RunEngine.emit_sync - ~RunEngine.halt - ~RunEngine.install_suspender - ~RunEngine.print_command_registry - ~RunEngine.register_command - ~RunEngine.remove_suspender - ~RunEngine.request_pause - ~RunEngine.request_suspend - ~RunEngine.reset - ~RunEngine.resume - ~RunEngine.stop - ~RunEngine.subscribe - ~RunEngine.unregister_command - ~RunEngine.unsubscribe - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~RunEngine.commands - ~RunEngine.ignore_callback_exceptions - ~RunEngine.loop - ~RunEngine.resumable - ~RunEngine.rewindable - ~RunEngine.state - ~RunEngine.suspenders - ~RunEngine.verbose - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.stop.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.stop.rst.txt deleted file mode 100644 index 5b0bf41585..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.stop.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.stop -================================== - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.stop \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.subscribe.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.subscribe.rst.txt deleted file mode 100644 index 79788d74be..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.subscribe.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.subscribe -======================================= - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.subscribe \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.unregister_command.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.unregister_command.rst.txt deleted file mode 100644 index fc404690b2..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.unregister_command.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.unregister\_command -================================================= - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.unregister_command \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.unsubscribe.rst.txt b/bluesky/_sources/generated/bluesky.run_engine.RunEngine.unsubscribe.rst.txt deleted file mode 100644 index d5675a56ad..0000000000 --- a/bluesky/_sources/generated/bluesky.run_engine.RunEngine.unsubscribe.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.run\_engine.RunEngine.unsubscribe -========================================= - -.. currentmodule:: bluesky.run_engine - -.. automethod:: RunEngine.unsubscribe \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.simulators.check_limits.rst.txt b/bluesky/_sources/generated/bluesky.simulators.check_limits.rst.txt deleted file mode 100644 index ce4c159dcb..0000000000 --- a/bluesky/_sources/generated/bluesky.simulators.check_limits.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.simulators.check\_limits -================================ - -.. currentmodule:: bluesky.simulators - -.. autofunction:: check_limits \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.simulators.plot_raster_path.rst.txt b/bluesky/_sources/generated/bluesky.simulators.plot_raster_path.rst.txt deleted file mode 100644 index 66f0ecaff9..0000000000 --- a/bluesky/_sources/generated/bluesky.simulators.plot_raster_path.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.simulators.plot\_raster\_path -===================================== - -.. currentmodule:: bluesky.simulators - -.. autofunction:: plot_raster_path \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.simulators.summarize_plan.rst.txt b/bluesky/_sources/generated/bluesky.simulators.summarize_plan.rst.txt deleted file mode 100644 index c1d84a2457..0000000000 --- a/bluesky/_sources/generated/bluesky.simulators.summarize_plan.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.simulators.summarize\_plan -================================== - -.. currentmodule:: bluesky.simulators - -.. autofunction:: summarize_plan \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.suspenders.SuspendBoolHigh.rst.txt b/bluesky/_sources/generated/bluesky.suspenders.SuspendBoolHigh.rst.txt deleted file mode 100644 index 28bfad8db3..0000000000 --- a/bluesky/_sources/generated/bluesky.suspenders.SuspendBoolHigh.rst.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendBoolHigh -================================== - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendBoolHigh - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendBoolHigh.__init__ - ~SuspendBoolHigh.get_futures - ~SuspendBoolHigh.install - ~SuspendBoolHigh.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendBoolHigh.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.suspenders.SuspendBoolLow.rst.txt b/bluesky/_sources/generated/bluesky.suspenders.SuspendBoolLow.rst.txt deleted file mode 100644 index 7c9dacd7d2..0000000000 --- a/bluesky/_sources/generated/bluesky.suspenders.SuspendBoolLow.rst.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendBoolLow -================================= - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendBoolLow - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendBoolLow.__init__ - ~SuspendBoolLow.get_futures - ~SuspendBoolLow.install - ~SuspendBoolLow.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendBoolLow.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.suspenders.SuspendCeil.rst.txt b/bluesky/_sources/generated/bluesky.suspenders.SuspendCeil.rst.txt deleted file mode 100644 index 8a52d0490e..0000000000 --- a/bluesky/_sources/generated/bluesky.suspenders.SuspendCeil.rst.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendCeil -============================== - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendCeil - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendCeil.__init__ - ~SuspendCeil.get_futures - ~SuspendCeil.install - ~SuspendCeil.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendCeil.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.suspenders.SuspendFloor.rst.txt b/bluesky/_sources/generated/bluesky.suspenders.SuspendFloor.rst.txt deleted file mode 100644 index fe3d9f3e29..0000000000 --- a/bluesky/_sources/generated/bluesky.suspenders.SuspendFloor.rst.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendFloor -=============================== - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendFloor - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendFloor.__init__ - ~SuspendFloor.get_futures - ~SuspendFloor.install - ~SuspendFloor.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendFloor.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.suspenders.SuspendWhenChanged.rst.txt b/bluesky/_sources/generated/bluesky.suspenders.SuspendWhenChanged.rst.txt deleted file mode 100644 index d895fe55dc..0000000000 --- a/bluesky/_sources/generated/bluesky.suspenders.SuspendWhenChanged.rst.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendWhenChanged -===================================== - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendWhenChanged - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendWhenChanged.__init__ - ~SuspendWhenChanged.get_futures - ~SuspendWhenChanged.install - ~SuspendWhenChanged.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendWhenChanged.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.suspenders.SuspendWhenOutsideBand.rst.txt b/bluesky/_sources/generated/bluesky.suspenders.SuspendWhenOutsideBand.rst.txt deleted file mode 100644 index 91a9d8504a..0000000000 --- a/bluesky/_sources/generated/bluesky.suspenders.SuspendWhenOutsideBand.rst.txt +++ /dev/null @@ -1,31 +0,0 @@ -bluesky.suspenders.SuspendWhenOutsideBand -========================================= - -.. currentmodule:: bluesky.suspenders - -.. autoclass:: SuspendWhenOutsideBand - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SuspendWhenOutsideBand.__init__ - ~SuspendWhenOutsideBand.get_futures - ~SuspendWhenOutsideBand.install - ~SuspendWhenOutsideBand.remove - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~SuspendWhenOutsideBand.tripped - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.DefaultDuringTask.rst.txt b/bluesky/_sources/generated/bluesky.utils.DefaultDuringTask.rst.txt deleted file mode 100644 index a55d1bb0f4..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.DefaultDuringTask.rst.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.utils.DefaultDuringTask -=============================== - -.. currentmodule:: bluesky.utils - -.. autoclass:: DefaultDuringTask - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~DefaultDuringTask.__init__ - ~DefaultDuringTask.block - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.DuringTask.block.rst.txt b/bluesky/_sources/generated/bluesky.utils.DuringTask.block.rst.txt deleted file mode 100644 index 199d1fdceb..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.DuringTask.block.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.DuringTask.block -============================== - -.. currentmodule:: bluesky.utils - -.. automethod:: DuringTask.block \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.DuringTask.rst.txt b/bluesky/_sources/generated/bluesky.utils.DuringTask.rst.txt deleted file mode 100644 index 18efe81dfb..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.DuringTask.rst.txt +++ /dev/null @@ -1,23 +0,0 @@ -bluesky.utils.DuringTask -======================== - -.. currentmodule:: bluesky.utils - -.. autoclass:: DuringTask - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~DuringTask.__init__ - ~DuringTask.block - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.FailedPause.rst.txt b/bluesky/_sources/generated/bluesky.utils.FailedPause.rst.txt deleted file mode 100644 index 4fdf842f57..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.FailedPause.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.FailedPause -========================= - -.. currentmodule:: bluesky.utils - -.. autoexception:: FailedPause \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.FailedStatus.rst.txt b/bluesky/_sources/generated/bluesky.utils.FailedStatus.rst.txt deleted file mode 100644 index 9fefe2ed77..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.FailedStatus.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.FailedStatus -========================== - -.. currentmodule:: bluesky.utils - -.. autoexception:: FailedStatus \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.IllegalMessageSequence.rst.txt b/bluesky/_sources/generated/bluesky.utils.IllegalMessageSequence.rst.txt deleted file mode 100644 index 8ead32fc5d..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.IllegalMessageSequence.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.IllegalMessageSequence -==================================== - -.. currentmodule:: bluesky.utils - -.. autoexception:: IllegalMessageSequence \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.InvalidCommand.rst.txt b/bluesky/_sources/generated/bluesky.utils.InvalidCommand.rst.txt deleted file mode 100644 index 310ff4a2d3..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.InvalidCommand.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.InvalidCommand -============================ - -.. currentmodule:: bluesky.utils - -.. autoexception:: InvalidCommand \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.Msg.rst.txt b/bluesky/_sources/generated/bluesky.utils.Msg.rst.txt deleted file mode 100644 index 31f9b49e58..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.Msg.rst.txt +++ /dev/null @@ -1,34 +0,0 @@ -bluesky.utils.Msg -================= - -.. currentmodule:: bluesky.utils - -.. autoclass:: Msg - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Msg.__init__ - ~Msg.count - ~Msg.index - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~Msg.args - ~Msg.command - ~Msg.kwargs - ~Msg.obj - ~Msg.run - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.NoReplayAllowed.rst.txt b/bluesky/_sources/generated/bluesky.utils.NoReplayAllowed.rst.txt deleted file mode 100644 index ea3b1061ec..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.NoReplayAllowed.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.NoReplayAllowed -============================= - -.. currentmodule:: bluesky.utils - -.. autoexception:: NoReplayAllowed \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.PersistentDict.directory.rst.txt b/bluesky/_sources/generated/bluesky.utils.PersistentDict.directory.rst.txt deleted file mode 100644 index 5bf3d39f17..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.PersistentDict.directory.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.PersistentDict.directory -====================================== - -.. currentmodule:: bluesky.utils - -.. autoproperty:: PersistentDict.directory \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.PersistentDict.rst.txt b/bluesky/_sources/generated/bluesky.utils.PersistentDict.rst.txt deleted file mode 100644 index a34674a8d6..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.PersistentDict.rst.txt +++ /dev/null @@ -1,40 +0,0 @@ -bluesky.utils.PersistentDict -============================ - -.. currentmodule:: bluesky.utils - -.. autoclass:: PersistentDict - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~PersistentDict.__init__ - ~PersistentDict.clear - ~PersistentDict.close - ~PersistentDict.flush - ~PersistentDict.get - ~PersistentDict.items - ~PersistentDict.keys - ~PersistentDict.pop - ~PersistentDict.popitem - ~PersistentDict.reload - ~PersistentDict.setdefault - ~PersistentDict.update - ~PersistentDict.values - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~PersistentDict.directory - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.PlanHalt.rst.txt b/bluesky/_sources/generated/bluesky.utils.PlanHalt.rst.txt deleted file mode 100644 index 4ed3f84c0f..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.PlanHalt.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.PlanHalt -====================== - -.. currentmodule:: bluesky.utils - -.. autoexception:: PlanHalt \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.ProgressBar.clear.rst.txt b/bluesky/_sources/generated/bluesky.utils.ProgressBar.clear.rst.txt deleted file mode 100644 index b42051e4a5..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.ProgressBar.clear.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.ProgressBar.clear -=============================== - -.. currentmodule:: bluesky.utils - -.. automethod:: ProgressBar.clear \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.ProgressBar.draw.rst.txt b/bluesky/_sources/generated/bluesky.utils.ProgressBar.draw.rst.txt deleted file mode 100644 index 9c51b33ed6..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.ProgressBar.draw.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.ProgressBar.draw -============================== - -.. currentmodule:: bluesky.utils - -.. automethod:: ProgressBar.draw \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.ProgressBar.rst.txt b/bluesky/_sources/generated/bluesky.utils.ProgressBar.rst.txt deleted file mode 100644 index 901da84168..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.ProgressBar.rst.txt +++ /dev/null @@ -1,25 +0,0 @@ -bluesky.utils.ProgressBar -========================= - -.. currentmodule:: bluesky.utils - -.. autoclass:: ProgressBar - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~ProgressBar.__init__ - ~ProgressBar.clear - ~ProgressBar.draw - ~ProgressBar.update - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.ProgressBar.update.rst.txt b/bluesky/_sources/generated/bluesky.utils.ProgressBar.update.rst.txt deleted file mode 100644 index 75a4d1f5d3..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.ProgressBar.update.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.ProgressBar.update -================================ - -.. currentmodule:: bluesky.utils - -.. automethod:: ProgressBar.update \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.ProgressBarManager.rst.txt b/bluesky/_sources/generated/bluesky.utils.ProgressBarManager.rst.txt deleted file mode 100644 index 01f81563a4..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.ProgressBarManager.rst.txt +++ /dev/null @@ -1,22 +0,0 @@ -bluesky.utils.ProgressBarManager -================================ - -.. currentmodule:: bluesky.utils - -.. autoclass:: ProgressBarManager - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~ProgressBarManager.__init__ - - - - - - \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.RampFail.rst.txt b/bluesky/_sources/generated/bluesky.utils.RampFail.rst.txt deleted file mode 100644 index 972a4f661a..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.RampFail.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.RampFail -====================== - -.. currentmodule:: bluesky.utils - -.. autoexception:: RampFail \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.RequestAbort.rst.txt b/bluesky/_sources/generated/bluesky.utils.RequestAbort.rst.txt deleted file mode 100644 index 5791bf10f2..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.RequestAbort.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.RequestAbort -========================== - -.. currentmodule:: bluesky.utils - -.. autoexception:: RequestAbort \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.RequestStop.rst.txt b/bluesky/_sources/generated/bluesky.utils.RequestStop.rst.txt deleted file mode 100644 index 86a26ad948..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.RequestStop.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.RequestStop -========================= - -.. currentmodule:: bluesky.utils - -.. autoexception:: RequestStop \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.RunEngineControlException.rst.txt b/bluesky/_sources/generated/bluesky.utils.RunEngineControlException.rst.txt deleted file mode 100644 index cdc795733b..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.RunEngineControlException.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.RunEngineControlException -======================================= - -.. currentmodule:: bluesky.utils - -.. autoexception:: RunEngineControlException \ No newline at end of file diff --git a/bluesky/_sources/generated/bluesky.utils.RunEngineInterrupted.rst.txt b/bluesky/_sources/generated/bluesky.utils.RunEngineInterrupted.rst.txt deleted file mode 100644 index 90980f10dd..0000000000 --- a/bluesky/_sources/generated/bluesky.utils.RunEngineInterrupted.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -bluesky.utils.RunEngineInterrupted -================================== - -.. currentmodule:: bluesky.utils - -.. autoexception:: RunEngineInterrupted \ No newline at end of file diff --git a/bluesky/_sources/hardware.rst.txt b/bluesky/_sources/hardware.rst.txt deleted file mode 100644 index 96511b01e5..0000000000 --- a/bluesky/_sources/hardware.rst.txt +++ /dev/null @@ -1,359 +0,0 @@ -How Bluesky Interfaces with Hardware -==================================== - -Overview --------- - -Bluesky interacts with hardware through a high-level abstraction, leaving the -low-level details of communication as a separate concern. In bluesky's view, -*all* devices are in a sense "detectors," in that they can be read. A subset -of these devices are "positioners" that can also be set (i.e., written to or -moved). - -In short, each device is represented by a Python object that has attributes and -methods with certain established names. We have taken pains to make this -interface as slim as possible, while still being general enough to address -every kind of hardware we have encountered. - -Specification -------------- - -.. _status_obj_api: - -Status object -+++++++++++++ - -The interface of a "status" object, which the ``RunEngine`` uses to -asynchronously monitor the compeletion of having triggered or set a device. - -.. class:: Status: - - .. attribute:: done - - boolean - - .. attribute:: success - - boolean - - If ``success`` is ``False`` when the Status is marked done, this is taken - to mean, "We have given up." For example, "The motor is stuck and will - never get where it is going." A ``FailedStatus`` exception will be raised - inside the RunEngine. - - .. attribute:: finished_cb - - a callback function that ``Status`` will call when it is marked done. - - It may be that ``Status`` is done before a function has been attached to - ``finished_cb``. In that case, the function should be called as soon as it - is attached. - - .. method:: watch(func) - - Subscribe to notifications about progress. Useful for progress bars. - - **Parameters** - - func : callable - Expected to accept the keyword arguments: - - * ``name`` - * ``current`` - * ``initial`` - * ``target`` - * ``unit`` - * ``precision`` - * ``fraction`` - * ``time_elapsed`` - * ``time_remaining`` - - Any given call to ``func`` may only include a subset of these - parameters, depending on what the status object knows about its own - progress. - -Readable Device -+++++++++++++++ - -The interface of a readable device: - -.. class:: ReadableDevice - - .. attribute:: name - - a human-readable string identifying the device - - .. attribute:: parent - - ``None``, or a reference to a parent device - - See the ``stage`` method below for the operational signifance of - ``parent``. - - .. method:: read() - - Return an OrderedDict mapping field name(s) to values and timestamps. - The field names must be strings. The values can be any JSON-encodable - type or a numpy array, which the RunEngine will convert to (nested) - lsits. The timestamps should be UNIX time (seconds since 1970). - - Example return value: - - .. code-block:: python - - OrderedDict(('channel1', - {'value': 5, 'timestamp': 1472493713.271991}), - ('channel2', - {'value': 16, 'timestamp': 1472493713.539238})) - - - .. method:: describe() - - Return an OrderedDict with exactly the same keys as the ``read`` - method, here mapped to metadata about each field. - - Example return value: - - .. code-block:: python - - OrderedDict(('channel1', - {'source': 'XF23-ID:SOME_PV_NAME', - 'dtype': 'number', - 'shape': []}), - ('channel2', - {'source': 'XF23-ID:SOME_PV_NAME', - 'dtype': 'number', - 'shape': []})) - - We refer to each entry as a "data key." These fields are required: - - * source (a descriptive string --- e.g., an EPICS Process Variable) - * dtype: one of the JSON data types: {'number', 'string', 'array'} - * shape: list of integers (dimension sizes) --- e.g., ``[5, 5]`` for a - 5x5 array. Use empty list ``[]`` to indicate a scalar. - - Optional additional fields (precision, units, etc.) are allowed. - The optional field ``external`` should be used to provide information - about references to externally-stored data, such as large image arrays. - - .. method:: trigger() - - Return a ``Status`` that is marked done when the device is done - triggering. - - If the device does not need to be triggered, simply return a ``Status`` - that is marked done immediately. - - .. method:: read_configuration() - - Same API as ``read`` but for slow-changing fields related to - configuration (e.g., exposure time). These will typically be read only - once per run. - - Of course, for simple cases, you can effectively omit this complexity - by returning an empty dictionary. - - .. method:: describe_configuration() - - Same API as ``describe``, but corresponding to the keys in - ``read_configuration``. - - .. attribute:: hints - - A dictionary of suggestions for best-effort visualization and - processing. This does not affect what data is read or saved; it is only - a suggestion to enable automated tools to provide helpful information - with minimal guidance from the user. See :ref:`hints`. - - .. method:: configure(*args, **kwargs) - - This can change the device's configuration in an arbitrary way. When - the RunEngine calls this method, it also emits a fresh Event Descriptor - because it assumes that the configuration in the previous Event - Descriptor might no longer be valid. - - Returns a tuple of the *old* result of ``read_configuration()`` and the - *new* result of ``read_configuration()``. - - *This concludes the required API. The following are optional.* - - .. method:: stage() - - An optional hook for "setting up" the device for acquisition. - - It should return a list of devices including itself and any other - devices that are staged as a result of staging this one. - (The ``parent`` attribute expresses this relationship: a device should - be staged/unstaged whenever its parent is staged/unstaged.) - - .. method:: unstage() - - A hook for "cleaning up" the device after acquisition. - - It should return a list of devices including itself and any other - devices that are unstaged as a result of unstaging this one. - - .. method:: subscribe(function) - - Optional, needed only if the device will be :doc:`monitored `. - - When the device has a new value ready, it should call ``function`` - asynchronously in a separate thread. - - .. method:: clear_sub(function) - - Remove a subscription. (See ``subscribe``, above.) - - .. method:: pause() - - An optional hook to do some device-specific work when the RunEngine - pauses. - - .. method:: resume() - - An optional hook to do some device-specific work when the RunEngine - resumes after a pause. - - -Movable (or "Settable") Device -+++++++++++++++++++++++++++++++ - -The interface of a movable device extends the interface of a readable device -with the following additional methods and attributes. The utility function -:func:`bluesky.utils.is_movable` can be used to check if an object meets the -expected interface of a Movable. - -.. class:: MovableDevice: - - .. method:: set(*args, **kwargs) - - Return a ``Status`` that is marked done when the device is done - moving. This is the only *required* method that the Movable interace - adds to the Readable one. - - .. method:: stop(success=True) - - Safely stop a device that may or may not be in motion. - The argument ``success`` is a boolean. - When ``success`` is true, bluesky is stopping the device as planned - and the device should stop "normally". - When ``success`` is false, something has gone wrong and the device - may wish to take defensive action to make itself safe. - - Optional: devices that cannot be stopped should not implement this - method. - - .. method:: check_value(*args, **kwargs) - - This should accept the same arguments as ``set``. It should raise an - Exception if the argument represent an illegal setting --- e.g. a - position that would move a motor outside its limits or a temperature - controller outside of its settable range. - - Optional: If this method is not present, simulators that check limits - such as :func:`bluesky.simulators.check_limits` may issue a warning but - should assume that all values are legal. - - .. attribute:: position - - A heuristic that describes the current position of a device as a - single scalar, as opposed to the potentially multi-valued description - provided by ``read()``. - - Optional: bluesky itself does not use the position attribute, but other - parts of the ecosystem might. - Developers are encouraged to implement this attribute where possible. - - -"Flyer" Interface -+++++++++++++++++ - -*For context on what we mean by "flyer", refer to the section on :doc:`async`.* - -The interface of a "flyable" device is separate from the interface of a readable -or settable device, though there is some overlap. - -.. class:: FlyableDevice: - - .. method:: kickoff() - - Begin acculumating data. Return a ``Status`` and mark it done when - acqusition has begun. - - .. method:: complete() - - Return a ``Status`` and mark it done when acquisition has completed. - - .. method:: collect() - - Yield dictionaries that are partial Event documents. They should - contain the keys 'time', 'data', and 'timestamps'. A 'uid' is added by - the RunEngine. - - .. method:: describe_collect() - - This is like ``describe()`` on readable devices, but with an extra - layer of nesting. Since a flyer can potentially return more than one - event stream, this is a dict of stream names (strings) mapped to a - ``describe()``-type output for each. - - *The remaining methods and attributes match ReadableDevice.* - - .. method:: configure(*args, **kwargs) - - same as for a readable device - - .. method:: read_configuration() - - same as for a readable device - - .. method:: describe_configuration() - - same as for a readable device - - .. attribute:: name - - same as for a readable device - - .. attribute:: parent - - same as for a readable device - - .. method:: stage() - - optional, same as for a readable device - - .. method:: unstage() - - optional, same as for a readable device - - .. method:: pause() - - optional, same as for a readable device - - .. method:: resume() - - optional, same as for a readable device - -Implementations ---------------- - -Real Hardware -+++++++++++++ - -The `ophyd -`_ package implements this interface for -a wide variety of hardware, communicating using -`EPICS `_ via the Python bindings -`pyepics `_.Other control -systems (Tango, LabView, etc.) could be integrated with bluesky in the future -by implementing this same interface. - -Simulated Hardware -++++++++++++++++++ - -A toy "test" implementation the interface is included in the -:mod:`ophyd.sim` module. These implementations act as simulated hardware, -and we use them extensively in examples, demos, and the test suite. They can -also be useful for exercising analysis workflows before running a real -experiment. API documentation is below. diff --git a/bluesky/_sources/hardware.txt b/bluesky/_sources/hardware.txt deleted file mode 100644 index 1ad2ccaf11..0000000000 --- a/bluesky/_sources/hardware.txt +++ /dev/null @@ -1,303 +0,0 @@ -How Bluesky Interfaces with Hardware -==================================== - -Overview --------- - -Bluesky interacts with hardware through a high-level abstraction, leaving the -low-level details of communication as a separate concern. In bluesky's view, -*all* devices are in a sense "detectors," in that they can be read. A subset -of these devices are "positioners" that can also be set (i.e., written to or -moved). - -In short, each device is represented by a Python object that has attributes and -methods with certain established names. We have taken pains to make this -interface as slim as possible, while still being general enough to address -every kind of hardware we have encountered. - -Implementations ---------------- - -Real Hardware -+++++++++++++ - -The `ophyd -`_ package implements this interface for -a wide variety of hardware, communicating using -`EPICS `_ via the Python bindings -`pyepics `_.Other control -systems (Tango, LabView, etc.) could be integrated with bluesky in the future -by implementing this same interface. - -Simulated Hardware -++++++++++++++++++ - -A toy "test" implementation the interface is included in the -``bluesky.examples`` module. These implementations act as simulated hardware, -and we use them extensively in examples, demos, and the test suite. They can -also be useful for exercising analysis workflows before running a real -experiment. API documentation is below. - -.. autoclass:: bluesky.examples.Reader -.. autoclass:: bluesky.examples.Mover - -Specification -------------- - -Status object -+++++++++++++ - -The interface of a "status" object, which the ``RunEngine`` uses to -asynchronously monitor the compeletion of having triggered or set a device. - -.. class:: Status: - - .. attribute:: done - - boolean - - .. attribute:: success - - boolean - - If ``success`` is ``False`` when the Status is marked done, this is taken - to mean, "We have given up." For example, "The motor is stuck and will - never get where it is going." A ``FailedStatus`` exception will be raised - inside the RunEngine. - - .. attribute:: finished_cb - - a callback function that ``Status`` will call when it is marked done. - - It may be that ``Status`` is done before a function has been attached to - ``finished_cb``. In that case, the function should be called as soon as it - is attached. - -Readable Device -+++++++++++++++ - -The interface of a readable device: - -.. class:: ReadableDevice - - .. attribute:: name - - a human-readable string identifying the device - - .. attribute:: parent - - ``None``, or a reference to a parent device - - See the ``stage`` method below for the operational signifance of - ``parent``. - - .. method:: read() - - Return an OrderedDict mapping field name(s) to values and timestamps. - The field names must be strings. The values can be any JSON-encodable - type or a numpy array, which the RunEngine will convert to (nested) - lsits. The timestamps should be UNIX time (seconds since 1970). - - Example return value: - - .. code-block:: python - - OrderedDict(('channel1', - {'value': 5, 'timestamp': 1472493713.271991}), - ('channel2', - {'value': 16, 'timestamp': 1472493713.539238})) - - - .. method:: describe() - - Return an OrderedDict with exactly the same keys as the ``read`` - method, here mapped to metadata about each field. - - Example return value: - - .. code-block:: python - - OrderedDict(('channel1', - {'source': 'XF23-ID:SOME_PV_NAME', - 'dtype': 'number', - 'shape': []}), - ('channel2', - {'source': 'XF23-ID:SOME_PV_NAME', - 'dtype': 'number', - 'shape': []})) - - We refer to each entry as a "data key." These fields are required: - - * source (a descriptive string --- e.g., an EPICS Process Variable) - * dtype: one of the JSON data types: {'number', 'string', 'array'} - * shape: ``None`` or a list of dimensions --- e.g., ``[5, 5]`` for a - 5x5 array - - Optional additional fields (precision, units, etc.) are allowed. - The optional field ``external`` should be used to provide information - about references to externally-stored data, such as large image arrays. - - .. method:: trigger() - - Return a ``Status`` that is marked done when the device is done - triggering. - - If the device does not need to be triggered, simply return a ``Status`` - that is marked done immediately. - - .. method:: read_configuration() - - Same API as ``read`` but for slow-changing fields related to - configuration (e.g., exposure time). These will typically be read only - once per run. - - Of course, for simple cases, you can effectively omit this complexity - by returning an empty dictionary. - - .. method:: describe_configuration() - - Same API as ``describe``, but corresponding to the keys in - ``read_configuration``. - - .. method:: configure(*args, **kwargs) - - This can change the device's configuration in an arbitrary way. When - the RunEngine calls this method, it also emits a fresh Event Descriptor - because it assumes that the configuration in the previous Event - Descriptor might no longer be valid. - - Returns a tuple of the *old* result of ``read_configuration()`` and the - *new* result of ``read_configuration()``. - - *This concludes the required API. The following are optional.* - - .. method:: stage() - - An optional hook for "setting up" the device for acquisition. - - It should return a list of devices including itself and any other - devices that are staged as a result of staging this one. - (The ``parent`` attribute expresses this relationship: a device should - be staged/unstaged whenever its parent is staged/unstaged.) - - .. method:: unstage() - - A hook for "cleaning up" the device after acquisition. - - It should return a list of devices including itself and any other - devices that are unstaged as a result of unstaging this one. - - .. method:: subscribe(function) - - Optional, needed only if the device will be :doc:`monitored `. - - When the device has a new value ready, it should call ``function`` - asynchronously in a separate thread. - - .. method:: clear_sub(function) - - Remove a subscription. (See ``subscribe``, above.) - - .. method:: pause() - - An optional hook to do some device-specific work when the RunEngine - pauses. - - .. method:: resume() - - An optional hook to do some device-specific work when the RunEngine - resumes after a pause. - - -Settable (Movable) Device -+++++++++++++++++++++++++ - -The interface of a settable device extends the interface of a readable device -with the following additional methods and attributes: - -.. class:: SettableDevice: - - .. method:: stop() - - Safely stop a device that may or may not be in motion. - - .. method:: set(*args, **kwargs) - - Return a ``Status`` that is marked done when the device is done - moving. - - .. attribute:: position - - a heuristic that describes the current position of a device as a - single scalar, as opposed to the potentially multi-valued description - provided by ``read()`` - -"Flyer" Interface -+++++++++++++++++ - -*For context on what we mean by "flyer", refer to the section on :doc:`async`.* - -The interace of a "flyable" device is separate from the interface of a readable -or settable device, though there is some overlap. - -.. class:: FlyableDevice: - - .. method:: kickoff() - - Begin acculumating data. Return a ``Status`` and mark it done when - acqusition has begun. - - .. method:: complete() - - Return a ``Status`` and mark it done when acquisition has completed. - - .. method:: collect() - - Yield dictionaries that are partial Event documents. They should - contain the keys 'time', 'data', and 'timestamps'. A 'uid' is added by - the RunEngine. - - .. method:: describe_collect() - - This is like ``describe()`` on readable devices, but with an extra - layer of nesting. Since a flyer can potentially return more than one - event stream, this is a dict of stream names (strings) mapped to a - ``describe()``-type output for each. - - *The remaining methods and attributes match ReadableDevice.* - - .. method:: configure(*args, **kwargs) - - same as for a readable device - - .. method:: read_configuration() - - same as for a readable device - - .. method:: describe_configuration() - - same as for a readable device - - .. attribute:: name - - same as for a readable device - - .. attribute:: parent - - same as for a readable device - - .. method:: stage() - - optional, same as for a readable device - - .. method:: unstage() - - optional, same as for a readable device - - .. method:: pause() - - optional, same as for a readable device - - .. method:: resume() - - optional, same as for a readable device diff --git a/bluesky/_sources/index.rst.txt b/bluesky/_sources/index.rst.txt deleted file mode 100644 index 77a314a699..0000000000 --- a/bluesky/_sources/index.rst.txt +++ /dev/null @@ -1,91 +0,0 @@ -Bluesky Data Collection Framework -================================= - -Bluesky is a library for experiment control and collection of scientific data -and metadata. It emphasizes the following virtues: - -* **Live, Streaming Data:** Available for inline visualization and processing. -* **Rich Metadata:** Captured and organized to facilitate reproducibility and - searchability. -* **Experiment Generality:** Seamlessly reuse a procedure on completely - different hardware. -* **Interruption Recovery:** Experiments are "rewindable," recovering cleanly - from interruptions. -* **Automated Suspend/Resume:** Experiments can be run unattended, - automatically suspending and resuming if needed. -* **Pluggable I/O:** Export data (live) into any desired format or database. -* **Customizability:** Integrate custom experimental procedures and commands, - and get the I/O and interruption features for free. -* **Integration with Scientific Python:** Interface naturally with numpy and - Python scientific stack. - -How to Use This Documentation ------------------------------ - -Start with the :doc:`tutorial`. It's a good place to start for everyone, and it -gives a good overview of the project in a narrative style. Read as far as you -need to solve your problem, and come back again if your needs change. Each -section of the tutorial adds a piece of complexity in exchange for deeper -customization. - -The remaining sections document bluesky's behavior in a less narrative style, -providing clear API documentation intermixed with some examples and explanation -of design and intent. - -Index ------ - -.. toctree:: - :caption: User Documentation - :maxdepth: 1 - - tutorial - plans - documents - metadata - callbacks - state-machine - simulation - progress-bar - event_descriptors - async - multi_run_plans - debugging - run_engine_api - utils - magics - from-pyepics-to-bluesky - comparison-with-spec - appendix - -.. toctree:: - :caption: Developer Documentation - :maxdepth: 1 - - hardware - msg - run_engine - api_changes - -.. toctree:: - :hidden: - :caption: Data Collection - - bluesky - ophyd - -.. toctree:: - :hidden: - :caption: Data Access and Management - - databroker - amostra - datamuxer - suitcase - -.. toctree:: - :hidden: - :caption: GitHub Links - - NSLS-II Repositories - Bug Reports diff --git a/bluesky/_sources/index.txt b/bluesky/_sources/index.txt deleted file mode 100644 index 4ff3f81d8d..0000000000 --- a/bluesky/_sources/index.txt +++ /dev/null @@ -1,58 +0,0 @@ -Bluesky Data Collection Framework -================================= - -Bluesky is a library for experiment control and collection of scientific data -and metadata. It emphasizes the following virtues: - -* **Live, Streaming Data:** Available for inline visualization and processing. -* **Rich Metadata:** Captured and organized to facilitate reproducibility and - searchability. -* **Experiment Generality:** Seamlessly reuse a procedure on completely - different hardware. -* **Interruption Recovery:** Experiments are "rewindable," recovering cleanly - from interruptions. -* **Automated Suspend/Resume:** Experiments can be run unattended, - automatically suspending and resuming if needed. -* **Pluggable I/O:** Export data (live) into any desired format or database. -* **Customizability:** Integrate custom experimental procedures and commands, - and get the I/O and interruption features for free. -* **Integration with Scientific Python:** Interface naturally with numpy and - Python scientific stack. - -Bluesky interacts with hardware through Python objects that are expected to -have a specified interface. This interface is implemented for "simulated" -motors and detectors included in the ``bluesky.examples`` module, which we use -here in documented examples and tests. - -To control actual hardware, an additional package is required. The `ophyd -`_ package implements the bluesky interface -for controlling motors, detectors, etc. via -`EPICS `_. Other control systems could be -integrated with bluesky in the future by presenting this same interface. - -Index ------ - -.. toctree:: - :caption: User Documentation - :maxdepth: 1 - - plans_intro - documents - metadata - plans - callbacks - state-machine - event_descriptors - async - debugging - cookbook/index - -.. toctree:: - :caption: Developer Documentation - :maxdepth: 1 - - hardware - msg - run_engine - api_changes diff --git a/bluesky/_sources/magics.rst.txt b/bluesky/_sources/magics.rst.txt deleted file mode 100644 index f22e26c2d6..0000000000 --- a/bluesky/_sources/magics.rst.txt +++ /dev/null @@ -1,199 +0,0 @@ -******************************* -IPython 'Magics' [Experimental] -******************************* - -.. warning:: - - This section covers an experimental feature of bluesky. It may be altered - or removed in the future. - -What Are 'Magics'? ------------------- - -IPython is an interactive Python interpreter designed for and by scientists. It includes a feature called "magics" --- convenience commands that aren't part of the Python language itself. For example, ``%history`` is a magic: - -.. ipython:: python - - a = 1 - b = 2 - %history - -The IPython documentation documents the -`complete list of built-in magics `_ -and, further, -`how to define custom magics `_. - -Bluesky Magics --------------- - -Bundled with bluesky are some IPython magics. They are intended for maintenance -tasks or casual sanity checks. **Intentionally, none of the magics save data; -for that you should use the RunEngine and plans.** - -To use the magics, first register them with IPython: - -.. ipython:: python - - from bluesky.magics import BlueskyMagics - get_ipython().register_magics(BlueskyMagics) - -For this example we'll use some simulated hardware. - -.. ipython:: python - - from ophyd.sim import motor1, motor2 - -Moving a Motor -~~~~~~~~~~~~~~ - -Suppose you want to move a motor interactively. You can use the ``%mov`` magic: - -.. ipython:: python - - %mov motor1 42 - -Where ``motor1`` refers to the actual ophyd object itself. -This is equivanent to: - -.. code-block:: python - - from bluesky.plan_stubs import mv - - RE(mv(motor1, 42)) - -but less to type. There is also a ``%movr`` magic for "relative move". They can -move multiple devices in parallel like so: - -.. ipython:: python - - %mov motor1 -3 motor2 3 - - -Note: Magics has changed from version v1.3.0 onwards. The previous method will -be described in the next section. - -Taking a reading using ``%ct`` (Post v1.3.0) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Before we may make use of the power of magics for counting, we must "label" -this hardware. To add a label, we must give hardware a ``labels={'mylabel'}`` -keyword argument. For example, here we initialize five simulated signals: two -motors, a shutter motor, an area detector and a point detector: - -.. ipython:: python - - import numpy as np - from ophyd.sim import SynAxis, SynSignal - motor1 = SynAxis(name='motor1', labels={'motors', 'scan_motors'}) - motor2 = SynAxis(name='motor2', labels={'motors', 'scan_motors'}) - shutter_motor = SynAxis(name='shutter_motor', labels={'motors', 'shutter_motors'}) - # create a fake area detector that returns a 2x2 array - area_detector = SynSignal(func=lambda: np.random.random((2, 2)), - name='adet1', labels={'detectors', 'area_detectors'}) - point_detector = SynSignal(func=lambda: np.random.random((1,)), - name='pointdet1', labels={'detectors', 'point_detectors'}) - -Now we have detectors and motors, with proper labels. - -Now suppose you want to take a quick reading of some devices and print the -results to the screen without saving them or doing any fancy processing. Use -the ``%ct`` magic: - -.. ipython:: python - - %ct area_detectors - -Where the names after count are a list of whitespace separated labels. In this -case, only ``area_detector`` will be counted. - -Running ``%ct`` without arguments looks for the ``detectors`` label by default: - -.. ipython:: python - - %ct - -In this case, we count both on the area detector and the point detector. - - -Aside on the automagic feature in IPython -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If IPython’s ‘automagic’ feature is enabled, IPython will even let you drop the -``%`` as long as the meaning is unambiguous: - -.. ipython:: python - - ct - ct = 3 # Now ct is a variable so automagic will not work... - ct - # ... but the magic still works. - %ct - -For what it’s worth, we recommend disabling 'automagic'. The ``%`` is useful -for flagging what follows as magical, non-Python code. - -Listing available motors using ``%wa`` (Post v1.3.0) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Finally, the ``%wa`` magic displays the a list of labeled devices. - -.. ipython:: python - - %wa scan_motors - -will display all motors used for a scan. -If blank, will print all labeled devices. - -.. ipython:: python - - %wa - -Note: It is possible to give a device more than one label. Thus it is possible -to have the same device in more than one list when calling ``%wa``. It is up to -the user to decide whether they want overlapping labels or not. - - -Comparison with SPEC -~~~~~~~~~~~~~~~~~~~~ - -The names of these magics, and the order of the parameters they take, are meant -to feel familiar to users of :doc:`SPEC `. - -Again, they must be registered with IPython before they can be used: - -.. code-block:: python - - from bluesky.magics import BlueskyMagics - get_ipython().register_magics(BlueskyMagics) - - -Taking a reading using ``%ct`` (Pre v1.3.0) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Previously, you could set a default list of detectors and them use ``%ct`` -without any parameters. This behaviour is deprecated. Do not use this: - -.. ipython:: python - :okwarning: - - BlueskyMagics.detectors = [area_detector, point_detector] - %ct - -This is no longer supported. - -Listing available motors using ``%wa`` (Pre v1.3.0) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Previously, it was possible to supply a list of motors. This feature is also -deprecated. Do not use this: - -.. ipython:: python - :okwarning: - - BlueskyMagics.positioners = [motor1, motor2] - %wa - -======================================================================= ============================== -Magic Plan Invoked -======================================================================= ============================== -``%mov`` :func:`~bluesky.plan_stubs.mv` -``%movr`` :func:`~bluesky.plan_stubs.mvr` -``%ct`` :func:`~bluesky.plans.count` -``%wa`` ("where all") Survey positioners* -======================================================================= ============================== diff --git a/bluesky/_sources/metadata.rst.txt b/bluesky/_sources/metadata.rst.txt deleted file mode 100644 index 3d6ee0528f..0000000000 --- a/bluesky/_sources/metadata.rst.txt +++ /dev/null @@ -1,492 +0,0 @@ -.. currentmodule:: bluesky.plans - -==================== - Recording Metadata -==================== - -Capturing useful metadata is the main objective of bluesky. The more -information you can provide about what you are doing and why you are -doing it, the more useful bluesky and downstream data search and -analysis tools can be. - -The term "metadata" can be a controversial term, one scientist's -"data" is another's "metadata" and classification is context- dependent. -The same exact information can be "data" in one -experiment, but "metadata" in a different experiment done on the exact -same hardware. -The `Document Model -`_ provides a framework -for deciding _where_ to record a particular piece of information. - -There are some things that we know *a priori* before doing an experiment; -where are we? who is the user? what sample are we looking at? what did -the user just ask us to do? These are all things that we can, in -principle, know independent of the control system. These are the -prime candidates for inclusion in the `Start Document -`_. -Downstream DataBroker provides tools to do rich searches on this data. -The more information you can include the better. - -There is some information that we need that is nominally independent of -any particular device but we need to consult the controls system -about. For example the location of important, but un-scanned motors -or the configuration of beam attenuators. If the values *should* be fixed over -the course of the experiment then this it is a good candidate for -being a "baseline device" either via the `Supplemental pre-processor -`_ -or explicitly in custom plans. This will put the readings in a separate stream -(which is a peer to the "primary" data). In principle, these values *could* be -read from the control system once and put into the Start document along with -the *a priori* information, however that has several draw backs: - -1. There is only ever 1 reading of the values so if they do drift during - data acquisition, you will never know. -2. We cannot automatically capture information about the device like - we do for data in Events. This includes things like the datatype, - units, and shape of the value and any configuration information about the - hardware it is being read from. - -A third class of information that can be called "metadata" is -configuration information of pieces of hardware. These are things -like the velocity of a motor or the integration time of a detector. -These readings are embedded in the `Descriptor -`_ -and are extracted from the hardware via the `read_configuration -`_ -method of the hardware. We expect that these values will not change over -the course of the experiment so only read them once. - -Information that does not fall into one of these categories, because -you expect it to change during the experiment, -should be treated as "data", either as an explicit part of the -experimental plan or via :ref:`async_monitoring`. - - -Adding to the Start Document -============================ - -When the RunEngine mints a Start document it includes structured data. That -information can be injected in via several mechanisms: - -1. entered interactively by the user at execution time -2. provided in the code of the *plan* -3. automatically inferred -4. entered by user once and stashed for reuse on all future plans - -If there is a conflict between these sources, the higher entry in this -list wins. The "closer" to a user the information originated the -higher priority it has. - - -1. Interactively, for One Use ------------------------------ - -Suppose we are executing some custom plan called ``plan``. - -.. code-block:: python - - RE(plan()) - -If we give arbitrary extra keyword arguments to ``RE``, they will be -interpreted as metadata. - -.. code-block:: python - - RE(plan(), sample_id='A', purpose='calibration', operator='Dan') - -The :ref:`run(s) ` --- i.e., datasets --- generated by ``plan()`` -will include the custom metadata: - -.. code-block:: python - - ... - 'sample_id': 'A', - 'purpose': 'calibration'. - 'operator': 'Dan', - ... - -If ``plan`` generates more that one run, all the runs will get this metadata. -For example, this plan generates three different runs. - -.. code-block:: python - - from bluesky.plans import count, scan - from ophyd.sim det1, det2, motor # simulated detectors, motor - - def plan(): - yield from count([det]) - yield from scan([det], motor, 1, 5, 5) - yield from count([det]) - -If executed as above: - -.. code-block:: python - - RE(plan(), sample_id='A', purpose='calibration', operator='Dan') - -each run will get a copy of the sample_id, purpose and operator metadata. - -2. Through a plan ------------------ - -Revisiting the previous example: - -.. code-block:: python - - def plan(): - yield from count([det]) - yield from scan([det], motor, 1, 5, 5) - yield from count([det]) - -we can pass different metadata for each run. Every -:ref:`built-in pre-assembled plan ` accepts a parameter -``md``, which you can use to inject metadata that applies only to that plan. - -.. code-block:: python - - def plan(): - yield from count([det], md={'purpose': 'calibration'}) # one - yield from scan([det], motor, 1, 5, 5, md={'purpose': 'good data'}) # two - yield from count([det], md={'purpose': 'sanity check'}) # three - -The metadata passed into ``RE`` is combined with the metadata passed in to each -plan. Thus, calling - -.. code-block:: python - - RE(plan(), sample_id='A', operator='Dan') - -generates these three sets of metadata: - -.. code-block:: python - - # one - ... - 'sample_id': 'A', - 'purpose': 'calibration'. - 'operator': 'Dan', - ... - - # two - ... - 'sample_id': 'A', - 'purpose': 'good data'. - 'operator': 'Dan', - ... - - # three - ... - 'sample_id': 'A', - 'purpose': 'sanity check'. - 'operator': 'Dan', - ... - -If there is a conflict, ``RE`` keywords takes precedence. So - -.. code-block:: python - - RE(plan(), purpose='test') - -would override the individual 'purpose' metadata from the plan, marking all -three as purpose=test. - -If you define your own plans, it is best practice have them take a keyword only -argument ``md=None``. This allows the hard-coded meta-data to be over-ridden -later: - -.. code-block:: python - - def plan(*, md=None): - md = md or {} # handle the default case - # putting unpacking **md at the end means it "wins" - # and if the user calls - # yield from plan(md={'purpose': bob}) - # it will over-ride these values - yield from count([det], md={'purpose': 'calibration', **md}) - yield from scan([det], motor, 1, 5, 5, md={'purpose': 'good data', **md}) - yield from count([det], md={'purpose': 'sanity check', **md}) - -This is consistent with all of the :ref:`preassembled_plans`. - -For more on injecting metadata via plans, refer to -:ref:`this section ` of the tutorial. - -.. note:: - - All of the built-in plans provide certain metadata automatically. Custom - plans are not *required* to provide any of this, but it is a nice pattern - to follow. - - * plan_name --- e.g., ``'scan'`` - * detectors --- a list of the names of the detectors - * motors --- a list of the names of the motors - * plan_args --- dict of keyword arguments passed to the plan - * plan_pattern -- function used to create the trajectory - * plan_pattern_module --- Python module where ``plan_pattern`` is defined - * plan_pattern_args --- dict of keyword arguments passed to - ``plan_pattern`` to create the trajectory - - The ``plan_name`` and ``plan_args`` together should provide sufficient - information to recreate the plan. The ``detectors`` and ``motors`` are - convenient keys to search on later. - - The ``plan_pattern*`` entries provide lower-level, more explicit - information about the *trajectory* ("pattern") generated by the plan, - separate from the specific detectors and motors involved. For complex - trajectories like spirals, this is especially useful. As a simple example, - here is the pattern-related metadata for :func:`scan`. - - .. code-block:: python - - ... - 'plan_pattern': 'linspace', - 'plan_pattern_module': 'numpy', - 'plan_pattern_args': dict(start=start, stop=stop, num=num) - ... - - Thus, one can re-create the "pattern" (trajectory) like so: - - .. code-block:: python - - numpy.linspace(**dict(start=start, stop=stop, num=num)) - -3. Automatically ----------------- - -For each run, the RunEngine automatically records: - -* 'time' --- In this context, the start time. (Other times are also recorded.) -* 'uid' --- a globally unique ID for this run -* 'plan_name' --- the function or class name of ``plan`` (e.g., 'count') -* 'plan_type'--- e.g., the Python type of ``plan`` (e.g., 'generator') - -The last two can be overridden by any of the methods above. The first two -cannot be overridden by the user. - -.. note:: - - If some custom plan does not specify a 'plan_name' and 'plan_type', the - RunEngine infers them as follows: - - .. code-block:: python - - plan_name = type(plan).__name__ - plan_type = getattr(plan, '__name__', '') - - These may be more or less informative depending on what ``plan`` is. They - are just heuristics to provide *some* information by default if the plan - itself and the user do not provide it. - -4. Interactively, for Repeated Use ----------------------------------- - -Each time a plan is executed, the current contents of ``RE.md`` are copied into -the metadata for all runs generated by the plan. To enter metadata once to -reuse on all plans, add it to ``RE.md``. - -.. code-block:: python - - RE.md['proposal_id'] = 123456 - RE.md['project'] = 'flying cars' - RE.md['dimensions'] = (5, 3, 10) - -View its current contents, - -.. code-block:: python - - RE.md - -delete a key you want to stop using, - -.. code-block:: python - - del RE.md['project'] # delete a key - -or use any of the standard methods that apply to -`dictionaries in Python `_. - -.. warning:: - - - In general we recommend against putting device readings in the Start - document. (The Start document is for who/what/why/when, things you - know before you start communicating with hardware.) It is *especially* - critical that you do not put device readings in the ``RE.md`` dictionary. - The value will remain until you change it and not track the state of the - hardware. This will result in recording out-of-date, incorrect data! - - This can be particularly dangerous if ``RE.md`` is backed by a - persistent data store (see next section) because out-of-date readings will - last across sessions. - - -The ``scan_id``, an integer that the RunEngine automatically increments at the -beginning of each scan, is stored in ``RE.md['scan_id']``. - -.. warning:: - - Clearing all keys, like so: - - .. code-block:: python - - RE.md.clear() # clear *all* keys - - will reset the ``scan_id``. The next time a plan is executed, the - RunEngine will start with a ``scan_id`` of 1 and set - - .. code-block:: python - - RE.md['scan_id'] = 1 - - Some readers may prefer to reset the scan ID to 1 at the beginning of a new - experiment; others way wish to maintain a single unbroken sequence of scan - IDs forever. - - From a technical standpoint, it is fine to have duplicate scan IDs. All - runs also have randomly-generated 'uid' ("unique ID") which is globally - unique forever. - -.. _md_persistence: - -Persistence Between Sessions ----------------------------- - -We provide a way to save the contents of the metadata stash ``RE.md`` between -sessions (e.g., exiting and re-opening IPython). - -In general, the ``RE.md`` attribute may be anything that supports the -dictionary interface. The simplest is just a plain Python dictionary. - -.. code-block:: python - - RE.md = {} - -To persist metadata between sessions, bluesky recommends -:class:`bluesky.utils.PersistentDict` --- a Python dictionary synced with a -directory of files on disk. Any changes made to ``RE.md`` are synced to the -file, so the contents of ``RE.md`` can persist between sessions. - -.. code-block:: python - - from bluesky.utils import PersistentDict - RE.md = PersistentDict('some/path/here') - -Bluesky does not provide a strong recommendation on that path; that a detail -left to the local deployment. - -Bluesky formerly recommended using :class:`~historydict.HistoryDict` --- a -Python dictionary backed by a sqlite database file. This approach proved -problematic with the threading introduced in bluesky v1.6.0, so it is no longer -recommended. If you have been following that recommendation, you should migrate -your metadata from `~historydict.HistoryDict` to -:class:`~bluesky.utils.PersistentDict`. First, update your configuration to -make ``RE.md`` a :class:`~bluesky.utils.PersistentDict` as shown above. Then, -migrate like so: - -.. code-block:: python - - from bluesky.utils import get_history - old_md = get_history() - RE.md.update(old_md) - -The :class:`~bluesky.utils.PersistentDict` object has been back-ported to -bluesky v1.5.6 as well. It is not available in 1.4.x or older, so once you move -to the new system, you must run bluesky v1.5.6 or higher. - -.. warning:: - - The ``RE.md`` object can also be set when the RunEngine is instantiated: - - .. code-block:: python - - # This: - RE = RunEngine(...) - - # is equivalent to this: - RE = RunEngine({}) - RE.md = ... - - As we stated - :ref:`at the start of the tutorial `, if you are - using bluesky at a user facility or with shared configuration, your - ``RE`` may already be configured, and defining a new ``RE`` as above can - result in data loss! If you aren't sure, it's safer to use ``RE.md = ...``. - - -Allowed Data Types ------------------- - -Custom metadata keywords can be mapped to: - -* strings --- e.g., ``task='calibration'`` -* numbers --- e.g., ``attempt=5`` -* lists or tuples --- e.g., ``dimensions=[1, 3]`` -* (nested) dictionaries --- e.g., ``dimensions={'width': 1, 'height': 3}`` - - -Required Fields ---------------- - -The fields: - -* **uid** -* **time** - -are reserved by the document model and cannot be set by the user. - -In current versions of bluesky, **no fields are universally required by bluesky -itself**. It is possible specify your own required fields in local -configuration. See :ref:`md_validator`. (At NSLS-II, there are facility-wide -requirements coming soon.) - - -Special Fields --------------- - -Arbitrary custom fields are allowed --- you can invent any names that are -useful to you. - -But certain fields are given special significance by bluesky's document model, -and are either disallowed are required to be a certain type. - -The fields: - -* **owner** -* **group** -* **project** - -are optional but, to facilitate searchability, if they are not blank they must -be strings. A non-string, like ``owner=5`` will produce an error that will -interrupt scan execution immediately after it starts. - -Similarly, the keyword **sample** has special significance. It must be either a -string or a dictionary. - -The **scan_id** field is expected to be an integer, and it is automatically -incremented between runs. If a scan_id is not provided by the user or stashed -in the persistent metadata from the previous run, it defaults to 1. - - -.. _md_validator: - -Validation ----------- - -Additional, customized metadata validation can be added to the RunEngine. -For example, to ensure that a run will not be executed unless the parameter -'sample_number' is specified, define a function that accepts a dictionary -argument and raises if 'sample_number' is not found. - -.. code-block:: python - - def ensure_sample_number(md): - if 'sample_number' not in md: - raise ValueError("You forgot the sample number.") - -Apply this function by setting - -.. code-block:: python - - RE.md_validator = ensure_sample_number - -The function will be executed immediately before each new run in opened. diff --git a/bluesky/_sources/metadata.txt b/bluesky/_sources/metadata.txt deleted file mode 100644 index 8dc00ed1b0..0000000000 --- a/bluesky/_sources/metadata.txt +++ /dev/null @@ -1,366 +0,0 @@ -.. currentmodule:: bluesky.plans - -Recording Metadata -================== - -Capturing useful metadata is the main objective of bluesky. The more -information you can provide about what you are doing and why you are doing it, -the more useful bluesky and downstream data search and analysis tools can be. - -When the RunEngine executes a plan, it attaches metadata to the data it -collects. It captures metadata that has been: - -1. entered interactively by the user at execution time -2. provided in the code of the *plan* -3. automatically inferred -4. entered by user once and stashed for reuse on all future plans - -If there is a conflict between these sources, the first entry in this list -wins. - -1. Interactively, for One Use ------------------------------ - -Suppose we are executing some custom plan called ``plan``. - -.. code-block:: python - - RE(plan()) - -If we give artibrary extra keyword arguments to ``RE``, they will be -interpreted as metadata. - -.. code-block:: python - - RE(plan(), sample_id='A', purpose='calibration', operator='Dan') - -The :ref:`run(s) ` --- i.e., datasets --- generated by ``plan()`` -will include the custom metadata: - -.. code-block:: python - - ... - 'sample_id': 'A', - 'purpose': 'calibration'. - 'operator': 'Dan', - ... - -If ``plan`` generates more that one run, all the runs will get this metadata. -For example, this plan generates three different runs. - -.. code-block:: python - - from bluesky.plans import count, scan - from bluesky.examples det1, det2, motor # simulated detectors, motor - - def plan(): - yield from count([det]) - yield from scan([det], motor, 1, 5, 5) - yield from count([det]) - -If executed as above: - -.. code-block:: python - - RE(plan(), sample_id='A', purpose='calibration', operator='Dan') - -each run will get a copy of the sample_id, purpose and operator metadata. - -2. Through a plan ------------------ - -Revisiting the previous example: - -.. code-block:: python - - def plan(): - yield from count([det]) - yield from scan([det], motor, 1, 5, 5) - yield from count([det]) - -we can pass different metadata for each run. Every -:ref:`built-in pre-assembled plan ` accepts a parameter -``md``, which you can use to inject metadata that applies only to that plan. - -.. code-block:: python - - def plan(): - yield from count([det], md={'purpose': 'calibration'}) # one - yield from scan([det], motor, 1, 5, 5, md={'purpose': 'good data'}) # two - yield from count([det], md={'purpose': 'sanity check'}) # three - -The metadata passed into ``RE`` is combined with the metadata passed in to each -plan. Thus, calling - -.. code-block:: python - - RE(plan(), sample_id='A', operator='Dan') - -generates these three sets of metadata: - -.. code-block:: python - - # one - ... - 'sample_id': 'A', - 'purpose': 'calibration'. - 'operator': 'Dan', - ... - - # two - ... - 'sample_id': 'A', - 'purpose': 'good data'. - 'operator': 'Dan', - ... - - # three - ... - 'sample_id': 'A', - 'purpose': 'sanity check'. - 'operator': 'Dan', - ... - -If there is a conflict, ``RE`` keywords takes precedence. So - -.. code-block:: python - - RE(plan(), purpose='test') - -would override the individual 'purpose' metadata from the plan, marking all -three as purpose=test. - -For more on injecting metadata via plans, refer to :ref:`customizing_metadata`. - -.. note:: - - All of the built-in plans provide certain metadata automatically. Custom - plans are not *required* to provide any of this, but it is a nice pattern - to follow. - - * plan_name --- e.g., ``'scan'`` - * detectors --- a list of the names of the detectors - * motors --- a list of the names of the motors - * plan_args --- dict of keyword arguments passed to the plan - * plan_pattern -- function used to create the trajectory - * plan_pattern_module --- Python module where ``plan_pattern`` is defined - * plan_pattern_args --- dict of keyword arguments passed to - ``plan_pattern`` to create the trajectory - - The ``plan_name`` and ``plan_args`` together should provide sufficient - information to recreate the plan. The ``detectors`` and ``motors`` are - convenient keys to search on later. - - The ``plan_pattern*`` entries provide lower-level, more explicit - information about the *trajectory* ("pattern") generated by the plan, - separate from the specific detectors and motors involved. For complex - trajectories like spirals, this is especially useful. As a simple example, - here is the pattern-related metadata for :func:`scan`. - - .. code-block:: python - - ... - 'plan_pattern': 'linspace', - 'plan_pattern_module': 'numpy', - 'plan_pattern_args': dict(start=start, stop=stop, num=num) - ... - - Thus, one can re-create the "pattern" (trajectory) like so: - - .. code-block:: python - - numpy.linspace(**dict(start=start, stop=stop, num=num)) - -3. Automatically ----------------- - -*This section is probably only useful to developers. If you are user just -trying to enter metadata, skip to the next section.* - -For each run, the RunEngine automatically records: - -* 'time' --- In this context, the start time. (Other times are also recorded.) -* 'uid' --- a globally unique ID for this run -* 'plan_name' --- the function or class name of ``plan`` (e.g., 'count') -* 'plan_type'--- e.g., the Python type of ``plan`` (e.g., 'generator') - -The last two can be overridden by any of the methods above. The first two -cannot be overridden by the user. - -.. note:: - - If some custom plan does not specify a 'plan_name' and 'plan_type', the - RunEngine infers them as follows: - - .. code-block:: python - - plan_name = type(plan).__name__ - plan_type = getattr(plan, '__name__', '') - - These may be more or less informative depending on what ``plan`` is. They - are just heuristics to provide *some* information by default if the plan - itself and the user do not provide it. - -4. Interactively, for Repeated Use ----------------------------------- - -Each time a plan is executed, the current contents of ``RE.md`` are copied into -the metadata for all runs generated by the plan. To enter metadata once to -reuse on all plans, add it to ``RE.md``. - -.. code-block:: python - - RE.md['proposal_id'] = 123456 - RE.md['project'] = 'flying cars' - RE.md['dimensions'] = (5, 3, 10) - -View its current contents, - -.. code-block:: python - - RE.md - -delete a key you want to stop using, - -.. code-block:: python - - del RE.md['project'] # delete a key - -or use any of the standard methods that apply to -`dictionaries in Python `_. - -The ``scan_id``, an integer that the RunEngine automatically increments at the -beginning of each scan, is stored in ``RE.md['scan_id']``. - -.. warning:: - - Clearing all keys, like so: - - .. code-block:: python - - RE.md.clear() # clear *all* keys - - will reset the ``scan_id``. The next time a plan is executed, the - RunEngine will start with a ``scan_id`` of 1 and set - - .. code-block:: python - - RE.md['scan_id'] = 1 - - Some readers may prefer to reset the scan ID to 1 at the beginning of a new - experiment; others way wish to maintain a single unbroken sequence of scan - IDs forever. - - From a technical standpoint, it is fine to have duplicate scan IDs. All - runs also have randomly-generated 'uid' ("unique ID") which is globally - unique forever. - -Persistence Between Sessions ----------------------------- - -We provide way to save the contents of the metadata stash ``RE.md`` between -sessions (e.g., exiting and re-opening IPython). - -In general, the ``RE.md`` attribute may be an ordinary Python dictionary or -anything that supports the dictionary interface. To persist metadata between -sessions, bluesky uses ``HistoryDict`` --- a Python dictionary backed by a -sqlite database file. Any changes made to ``RE.md`` are synced to the file -before IPython exits. - -The easiest way to create a ``HistoryDict`` is to use the convenience function, -``get_history``. It searches for a pre-existing history file in one of several -standard locations and, if it doesn't find one, it creates a new one. (See the -``get_history`` documentation below for details.) - -.. code-block:: python - - from bluesky.utils import get_history - RE = RunEngine(get_history()) - -Alternatively, create a ``HistoryDict`` manually anywhere you please: - -.. code-block:: python - - from historydict import HistoryDict - h = HistoryDict('your/path/here') - RE = RunEngine(h) - -.. autofunction:: bluesky.utils.get_history - -See also the -`historydict documentation `_. - -Allowed Data Types ------------------- - -Custom metadata keywords can be mapped to: - -* strings --- e.g., ``task='calibration'`` -* numbers --- e.g., ``attempt=5`` -* lists or tuples --- e.g., ``dimensions=[1, 3]`` -* (nested) dictionaries --- e.g., ``dimensions={'width': 1, 'height': 3}`` - -Special Fields --------------- - -Arbitrary custom fields are allowed --- you can invent any names that are -useful to you. - -But certain fields are given special significance by bluesky's document model, -and are either disallowed are required to be a certain type. - -The fields: - -* **owner** -* **group** -* **project** - -are optional but, to facilitate searchability, if they are not blank they must -be strings. A non-string, like ``owner=5`` will produce an error that will -interrupt scan execution immediately after it starts. - -Similarly, the keyword **sample** has special significance. It must be either a -string or a dictionary. - -The **scan_id** field is expected to be an integer, and it is automatically -incremented between runs. If a scan_id is not provided by the user or stashed -in the persistent metadata from the previous run, it defaults to 1. - -The fields: - -* **uid** -* **time** - -are reserved by the document model and cannot be set by the user. - -Required Fields ---------------- - -In current versions of bluesky, **no fields are universally required by bluesky -itself**. It is possible specify your own required fields in local -configuration. See :ref:`md_validator`. (At NSLS-II, there are facility-wide -requirements coming soon.) - -.. _md_validator: - -Metadata Validator ------------------- - -Additional, customized metadata validation can be added to the RunEngine. -For example, to ensure that a run will not be executed unless the parameter -'sample_number' is specified, define a function that accepts a dictionary -argument and raises if 'sample_number' is not found. - -.. code-block:: python - - def ensure_sample_number(md): - if 'sample_number' not in md: - raise ValueError("You forgot the sample number.") - -Apply this function by setting - -.. code-block:: python - - RE.md_validator = ensure_sample_number - -The function will be executed immediately before each new run in opened. diff --git a/bluesky/_sources/msg.rst.txt b/bluesky/_sources/msg.rst.txt deleted file mode 100644 index ce09e43c35..0000000000 --- a/bluesky/_sources/msg.rst.txt +++ /dev/null @@ -1,472 +0,0 @@ -.. _msg: - -Message Protocol -================ - -*Note: This is a technical document not optimized for user readability.* - -Overview --------- - -A *plan* is a sequence of atomic operations describing a data acquisition -procedure. Each operation is represented by a ``bluesky.Msg`` ("message") -object. A plan may be implemented as a simple list of messages: - -.. code-block:: python - - from bluesky import Msg - - # (Behold, the most boring data acquisition ever conducted!) - plan = [Msg('open_run'), Msg('close_run')] - -or as a generator the yields messages one at time: - -.. code-block:: python - - def plan(): - yield Msg('open_run') - yield Msg('close_run') - -The above examples are equivalent. For more sophisticated uses, the second one -is more powerful, as it can incorporate loops, conditionals, adaptive logic --- -generally any Python code. - -But, crucially, the plan code itself must not communicate with hardware. -(You should never put ``epics.caput(...)`` in a plan!) Rather, each operation -is represented by a ``Msg`` object that *describes* what should be done. This -makes it safe to introspect the plan for error-checking, simulation, and -visualization purposes --- without touching real hardware. For example, we -could print each message in the plan like so: - -.. code-block:: python - - plan = [Msg('open_run'), Msg('close_run')] - - # a very, very simple 'plan simulator' - for msg in plan: - print(msg) - -A ``Msg`` has five members, accessible as attributes: - -- command -- obj -- args -- kwargs -- run - -where ``command`` must be one of a controlled list of commands, ``obj`` is the -object (i.e. Device) to apply the command to, if applicable, ``args`` and -``kwargs`` are arguments to the command and ``run`` is a user-defined run key. -The run key is used by Run Engine to associate each message with one of the open runs, -manage the state of each open run, and route run data to a separate set of callbacks -(see documentation on Multi-Run Plans). - -To execute the plan, the :doc:`RunEngine ` consumes it, one message at a time. - -.. code-block:: python - - def very_simple_run_engine(plan): - for msg in plan: - # Process the msg. - -The ``RunEngine`` has a registry which is used to dispatch the ``Msg`` objects -based on the value of the ``Msg.command``. For example, if the RunEngine -receives the message ``Msg('set', motor, 5)``, the RunEngine will: - -1. Identify that the command for this message is ``'set'``. -2. Look up ``'set'`` in its command registry and find that it is mapped to - ``RunEngine._set``. -3. Pass ``Msg('set', motor, 5)`` to its ``_set`` method. -4. Inside ``_set``, call ``motor.set(5)``. (This is where the actual - communication with hardware occurs.) -5. Update some internal caches that will be useful later. For example, it will - keep track of that fact that ``motor`` may be in motion so that it can stop - it safely if an error occurs. This illustrates another important reason that - plans must always yield messages to interact with hardware and absolutely - never communicate with hardware directly. Calling ``epics.caput`` inside a - plan prevents the RunEngine from knowing about it and thus circumvents - its facilities for putting devices in a safe state in the event of an - unexpected exit or error. - -A standard set of commands are registered by default. By convention, a ``Msg`` -with the command ``'name'`` is mapped to a coroutine method on the RunEngine -named ``_name``, as in ``'set'`` -> ``RunEngine._set`` in the example above. -Users can register their own coroutines to add custom commands, though this is -very rarely necessary. - -Some commands do not involve communication with hardware. For example, -``Msg('sleep', None, 5)`` causes the RunEngine to sleep for 5 seconds. ``None`` -is a placeholder for the "object" (Device) which is not applicable for a -``'sleep'`` command. Just as plans should never communicate with hardware -directly, they should also never employ long blocking calls like -``time.sleep()``. Instead, the ``'sleep'`` command, mapped to -``RunEngine._sleep``, integrates with the RunEngine's event loop to sleep in a -non-blocking way that allows for the RunEngine to stay responsive in the -meantime --- watching for user interruptions and possibility collecting data -asynchronously in the background. - -Other commands are used to control metadata and I/O. For example, -``Msg('open_run')`` and ``Msg('close_run')`` delineate the scope of one run. -Any keyword arguments passed to the ``'open_run'`` message are interpreted as -metadata, encoded into the RunStart document. - -The following is a comprehensive overview of the built-in commands. - -.. _commands: - -Commands --------- - -.. warning:: - - This section of the documentation is incomplete. - -These are the 'built in' commands, some of which are deeply tied to the -state of the `RunEngine` instance. - -create -++++++ - -This command tells the run engine that it should start to collect the results -of ``read`` to create an event. If this is called twice without a ``save`` or -``drop`` between them it is an exception (as you can not have more than one -open event going at a time). - -This relies very heavily on the internal state of the run engine and should not -be overridden by the user. - -This call returns `None` back to the co-routine. - -This ignores all parts of the `Msg` except the command. - -save -++++ - -This is the pair to ``create`` which bundles and causes ``Event`` documents to -be emitted. This must be called after a ``create`` or a the scan will die and -raise `IllegalMessageSequence`. - -This relies very heavily on the internal state of the run engine and should not -be messed with. - -This call returns `None` back to the co-routine. - -This ignores all parts of the `Msg` except the command. - -read -++++ - -This causes `read` to be called on the ``obj`` in the message :: - - msg.obj.read(*msg.args, **msg.kwargs) - -Anything that is read between a ``create`` and ``save`` will be bundled into -a single event. - -This relies very heavily on the internal state of the run engine and should not -be messed with. - -Returns the dictionary returned by `read` to the co-routine. - -The ``args`` and ``kwargs`` parts of the message are passed to the `read` -method. - - -null -++++ - -This is a null message and is ignored by the run engine. This exists to make -the algebra work. - -Returns `None` to the co-routine. - -Ignores all values in the `Msg` except the command. - -set -+++ - -Tells a ``Mover`` object to move. Currently this mimics the epics-like logic -of immediate motion. - -stage and unstage -+++++++++++++++++ -Instruct the RunEngine to stage/unstage the object. This calls -``obj.stage()``/``obj.unstage``. - -Expected message objects are:: - - Msg('stage', object) - Msg('unstage', object) - -which results in these calls:: - - staged_devices = object.stage() - unstaged_devices = object.unstage() - -where ``staged_devices``/``unstaged_devices`` are a list of the -``ophyd.Device`` (s) that were (un)staged, not status objects. - -One may wonder why the return is a list of Devices as opposed to Status -objects, such as in ``set`` and similar ``Msg`` s. -This was debated for awhile. Operations performed during staging are supposed -to involve twiddling configuration, and should happen fast. Staging should not -involve lengthy set calls. - -Why a list of the objects staged? Staging a Device causes that Device's -component Devices (if any) to also be staged. All of these children are added -to a list, along with [self], and returned by Device.stage(), so that the plan -can keep track of what has been staged, like so:: - - devices_staged = yield Msg('stage', device) - -Why would the plan want to know that? It needs to avoid accidentally trying to -stage something twice, such as a staging a parent and then trying to also stage -its child. It's important to avoid that because staging something redundantly -raises an error. - - -trigger -+++++++ - -This will call the ``obj.trigger`` method and cache the returned status object -and caches the returned status object. - - -sleep -+++++ - -Sleep the event loop. - -wait -++++ - -Block progress until every object that was triggered or set the keyword -argument `group=` is done. - -Expected message object is: - -Msg('wait', group=) - -where ```` is any hashable key. - -wait_for -++++++++ -Instruct the ``RunEngine`` to wait for this ``asyncio.Future`` object to be -done. This allows for external arbitrary control of the ``RunEngine``. -Ex :: - - from asyncio.futures import Future - future = Future() - future.done() # will give false - RE(Msg('wait_for', [lambda : future ,])) - # this sets the future to done - future.set_result(3) - future.done() # will give True - - -input -+++++ -Process an input. Allows for user input during a run. - -Examples:: - - Msg('input', None) - Msg('input', None, prompt='>') # customize prompt - - -checkpoint -++++++++++ - -Instruct the RunEngine to create a checkpoint so that we can rewind to this -point if necessary. - -clear_checkpoint -++++++++++++++++ -Clear a set checkpoint. - -rewindable -++++++++++ - -pause -+++++ - -Request the run engine to pause - -Expected message object is:: - - Msg('pause', defer=False, name=None, callback=None) - - -kickoff -+++++++ - -Start a flyscan object. - -collect -+++++++ - -Collect data cached by a flyer and emit descriptor and event documents. -This calls the ``obj.collect()`` method. - -complete -++++++++ - -Tell a flyer, 'stop collecting, whenever you are ready'. - -This calls the method ``obj.complete()`` of the given object. The flyer returns -a status object. Some flyers respond to this command by stopping collection and -returning a finished status object immediately. Other flyers finish their given -course and finish whenever they finish, irrespective of when this command is -issued. - - -configure -+++++++++ - -Configure an object. - -Expected message object is:: - - Msg('configure', object, *args, **kwargs) - -which results in this call:: - - object.configure(*args, **kwargs) - - -subscribe -+++++++++ -Add a subscription after the run has started. - -This, like subscriptions passed to __call__, will be removed at the -end by the RunEngine. - -Expected message object is: - - Msg('subscribe', None, callback_function, document_name) - -where `document_name` is one of: - - {'start', 'descriptor', 'event', 'stop', 'all'} - -and `callback_function` is expected to have a signature of: - - ``f(name, document)`` - - where name is one of the ``document_name`` options and ``document`` - is one of the document dictionaries in the event model. - -See the docstring of bluesky.run_engine.Dispatcher.subscribe() for more -information. - -unsubscribe -+++++++++++ - -Remove a subscription during a call -- useful for a multi-run call -where subscriptions are wanted for some runs but not others. - -Expected message object is:: - - Msg('unsubscribe', None, TOKEN) - Msg('unsubscribe', token=TOKEN) - -where ``TOKEN`` is the return value from ``RunEngine._subscribe()`` - -open_run -++++++++ -Instruct the RunEngine to start a new "run" - -Expected message object is:: - - Msg('open_run', None, **kwargs) - -where ``**kwargs`` are any additional metadata that should go into the RunStart -document - -close_run -+++++++++ - -Instruct the RunEngine to write the RunStop document - -Expected message object is:: - - Msg('close_run', None, exit_status=None, reason=None) - -if *exit_stats* and *reason* are not provided, use the values -stashed on the RE. - - -drop -++++ - -Drop a bundle of readings without emitting a completed Event document. - -This is a command that abandons previous ``create`` and ``read`` commands -without emitting an event. This can be used to drop known bad events -(e.g. no beam) and keep the event document stream clean. It is safe to start -another ``create``, ``read``, ``save`` sequence after a ``drop``. - -This must be called after a ``create`` or a the scan will die and raise -`IllegalMessageSequence`. - -This call returns `None` back to the co-routine. - -This ignores all parts of the `Msg` except the command. - - -monitor -+++++++ -Monitor a signal. Emit event documents asynchronously. - -A descriptor document is emitted immediately. Then, a closure is -defined that emits Event documents associated with that descriptor -from a separate thread. This process is not related to the main -bundling process (create/read/save). - -Expected message object is:: - - Msg('monitor', obj, **kwargs) - Msg('monitor', obj, name='event-stream-name', **kwargs) - -where kwargs are passed through to ``obj.subscribe()`` - - -unmonitor -+++++++++ - -Stop monitoring; i.e., remove the callback emitting event documents. - -Expected message object is:: - - Msg('unmonitor', obj) - - -stop -++++ - -Stop a device. - -Expected message object is:: - - Msg('stop', obj) - -This amounts to calling ``obj.stop()``. - - -Registering Custom Commands ---------------------------- - -The RunEngine can be taught any new commands. They can be registered using the -following methods. - -.. automethod:: bluesky.run_engine.RunEngine.register_command - :noindex: - -.. automethod:: bluesky.run_engine.RunEngine.unregister_command - :noindex: - -.. autoattribute:: bluesky.run_engine.RunEngine.commands - :noindex: - -.. automethod:: bluesky.run_engine.RunEngine.print_command_registry - :noindex: diff --git a/bluesky/_sources/msg.txt b/bluesky/_sources/msg.txt deleted file mode 100644 index 7947868902..0000000000 --- a/bluesky/_sources/msg.txt +++ /dev/null @@ -1,129 +0,0 @@ -.. _msg: - -Message Protocol -================ - -*Note: This is a technical document not optimized for user readability.* - -Overview --------- - -The `bluesky.Msg` object is a `namedtuple` subclass which has the fields - -- command -- obj -- args -- kwargs - -``command`` must be one of a controlled list of commands, ``obj`` is the -object to apply the command to and ``args`` and ``kwargs`` are arguments to -the command. Any ``args`` or ``kwargs`` not consumed by the run engine are -passed through to the calls on the objects. - -The `RunEngine` has a registry which is used to dispatch the `Msg` objects -based on the value of the `Msg.cmd`. By default a basic set of commands are -registered, but users can register their own functions to add custom commands. - -.. _commands: - - -Commands --------- - -.. warning:: - - This section of the documentation is incomplete. - -These are the 'built in' commands, some of which are deeply tied to the -state of the `RunEnigne` instance. - -create -++++++ - -This command tells the run engine that it should start to collect the results of -``read`` to create an event. If this is called twice without a ``save`` between -them it is an exception (as you can not have more than one open event going at a time). - -This relies very heavily on the internal state of the run engine and should not -be overridden by the user. - -This call returns `None` back to the co-routine. - -This ignores all parts of the `Msg` except the command. - -save -++++ - -This is the pair to ``create`` which bundles and causes ``Event`` documents to be -emitted. This must be called after a ``create`` or a the scan will die and raise -`IllegalMessageSequence`. - -This relies very heavily on the internal state of the run engine and should not -be messed with. - -This call returns `None` back to the co-routine. - -This ignores all parts of the `Msg` except the command. - -read -++++ - -This causes `read` to be called on the ``obj`` in the message :: - - msg.obj.read(*msg.args, **msg.kwargs) - -Anything that is read between a ``create`` and ``save`` will be bundled into -a single event. - -This relies very heavily on the internal state of the run engine and should not -be messed with. - -Returns the dictionary returned by `read` to the co-routine. - -The ``args`` and ``kwargs`` parts of the message are passed to the `read` method. - - -null -++++ - -This is a null message and is ignored by the run engine. This exists to make the algebra work. - -Returns `None` to the co-routine. - -Ignores all values in the `Msg` except the command. - -set -+++ - -Tells a ``Mover`` object to move. Currently this mimics the epics-like logic of immediate -motion - -trigger -+++++++ - -sleep -+++++ - -wait -++++ - -checkpoint -++++++++++ - -pause -+++++ - -collect -+++++++ - -kickoff -+++++++ - -Registering Custom Commands ---------------------------- - -The RunEngine can be taught any new commands. They can be registered using the -following methods. - -.. automethod:: bluesky.run_engine.RunEngine.register_command -.. automethod:: bluesky.run_engine.RunEngine.unregister_command diff --git a/bluesky/_sources/multi_run_plans.rst.txt b/bluesky/_sources/multi_run_plans.rst.txt deleted file mode 100644 index d348566aa8..0000000000 --- a/bluesky/_sources/multi_run_plans.rst.txt +++ /dev/null @@ -1,346 +0,0 @@ -Multi-Run Plans -=============== - -Introduction ------------- - -This section is a brief tutorial on multi-run plans (introduced in Bluesky v1.6.0). -A traditional single-run plan contains a set of instructions for performing only one run, -which is assigned a scan ID and a UID. When a multi-run plan is executed by the Run Engine, multiple -runs can be performed as part of a single plan. Data from each run can be independently -displayed and saved to the database via Databroker. Prior versions of Bluesky supported -only sequential execution of multiple runs within a plan: building larger plans by creating -a sequence of smaller plans and preassembled plans shipped with Bluesky is a standard -practice. In Bluesky v1.6.0 a number of features were introduced to allow plans -with nested runs. Two runs are considered nested if one 'outer' run is interrupted, another -'inner' run is executed, and then the first run is resumed and completed. The number of levels -of nesting is not limited by Bluesky. Interruptions can be initiated by the plan itself -(simply by opening another run before closing currently executed run) or externally (e.g. -by triggering a suspender and causing execution of pre- or post-plan). This tutorial includes -a brief explanation of the new Bluesky features for supporting multi-run plans and several -examples that demonstrate the implementation of plans that contain sequential, nested and recursive -runs. - -Definition of a 'Run' ---------------------- - -From the point of view of Bluesky, a run is a sequence of instructions (messages) for controlling -the instrumental equipment that starts with `open_run` and ends with `close_run` message. -We may also apply the term 'run' to a block of code which generates such a sequence of messages. -Data from each run is bundled together via an assigned distinct Scan ID and UID. The set of documents -is also generated for each run, including mandatory 'start' and 'stop' documents. The documents -can be processed by callbacks (such as BestEffortCallback) and saved to the database via Databroker. - -In the plan, the run may be defined by explicitely enclosing the code in `bps.open_run()` and -`bps.close_run()` stubs: - -.. code-block:: python - - # Using 'bps.open_run()' and 'bps.close_run()' stubs to define a run - - import bluesky.plan_stubs as bps - from bluesky import RunEngine - - RE = RunEngine({}) - - def sample_plan(): - ... - yield from bps.open_run(md={}) # 'md' - metadata to be added to the 'start' document - ... - < code that controls execution of the scan > - ... - yield from bps.close_run() - - RE(sample_plan()) - -or using `@bpp.run_decorator`, which inserts `open_run` and `close_run` control messages -before and after the sequnce generated by the enclosed code: - -.. code-block:: python - - # Using 'bpp.run_decorator' to define a run - - import bluesky.preprocessors as bpp - from bluesky import RunEngine - - RE = RunEngine({}) - - @bpp.run_decorator(md={}) # 'md' - metadata to be added to the 'start' document - def sample_plan(): - ... - < code that controls execution of the scan > - ... - - RE(sample_plan()) - -The rules for basic Bluesky plans require that the currently running scan is closed before -the next scan is opened, therefore the following code works: - -.. code-block:: python - - # This code works, since the first run is closed before the second one is opened - - import bluesky.plan_stubs as bps - from bluesky import RunEngine - - RE = RunEngine({}) - - def sample_plan(): - yield from bps.open_run(md={}) - < code that controls execution of the scan > - yield from bps.close_run() # Closing the first run (scan) - yield from bps.open_run(md={}) # Opening the second run (scan) - < code that controls execution of the scan > - yield from bps.close_run() - - RE(sample_plan()) - -but the following code fails: - -.. code-block:: python - - # This code fails, since the second run is opened before the first run is closed - - import bluesky.plan_stubs as bps - from bluesky import RunEngine - - RE = RunEngine({}) - - def sample_plan(): - yield from bps.open_run(md={}) # Opening the first run - < code that controls execution of the scan > - yield from bps.open_run(md={}) # Opening the second run before the first one is closed - < code that controls execution of the scan > - yield from bps.close_run() - yield from bps.close_run() - - RE(sample_plan()) - - -Note, that the preassembled plans, such as `bluesky.plans.count` or `bluesky.plans.list_scan`, -are complete single-run plans, enclosed in `open_run` and `close_run` messages, therefore -the following code fails as well: - -.. code-block:: python - - # This code fails while attempting to start a preassembled plan from an open run - - import bluesky.plan_stubs as bps - from bluesky.plans import count - from bluesky import RunEngine - - RE = RunEngine({}) - - def sample_plan(): - yield from bps.open_run(md={}) # Starting the first run - < code that controls execution of the scan > - yield from bpp.count() # Attempting to run a preassembled plan from an open run - yield from bps.close_run() - - RE(sample_plan()) - -An example of the situation when a preassembled plan is called from another open run is -when a preassembled plan is included in a suspender pre- or post-plan. When the suspender is -triggered, the current run is interrupted (not closed) and the pre- or post-plan attempts to open -another run (the mechanism is the same as in the case of nested runs, see below). As a result, -Run Engine fails for the same reason as in the two previous code examples. The new multi-run plan -Bluesky features allow to implement nested plans, as well as include full-featured scans -in pre- and post-plans. - -Bluesky Features for Support of Multi-run Plans ------------------------------------------------ - -In order to handle simultaneously open runs within a plan, Run Engine is looking at the run key attribute -of each control message to decide which scan is currently being executed. The default value for the run key -is `None`, but it could be manually set in the plan for any block of code which define the run. A run key -value may be of any type, but it is **strongly** recommended that manually assigned run keys are -human-readable informative strings. - -The new 'inner' run can be opened from within the 'outer' run only if the run keys of the 'inner' and -'outer' scans are different. Otherwise the plan exectuion fails. - -The run key is used by Run Engine - -* to maintain the state of each run independently from other open runs; - -* to include run metadata, such as scan ID and UID, into the emitted documents. (Metadata is then used - to route the documents to the appropriate callbacks. If documents are saved using Databroker, the metadata - allows to associate documents with runs and retrieve run data from the database.) - -Run key is assigned to a block of code using `bpp.set_run_key_wrapper` or `@bpp.set_run_key_decorator`: - -.. code-block:: python - - import bluesky.preprocessors as bpp - from bluesky import RunEngine - - # Using decorator - @bpp.set_run_key_decorator("run_key_example_1") - @bpp.run_decorator(md={}) - def sample_plan(): - ... - < code that controls execution of the run > - ... - - RE(sample_plan()) - - from bluesky.plans import scan - from ophyd.sim import hw - det, motor = hw().det, hw().motor - - # Using wrapper - s = scan([det], motor, -1, 1, 10) - s_wrapped = bpp.set_run_key_wrapper(s, "run_key_example_2") - RE(s_wrapped) - -The implementation of `@bpp.set_run_key_decorator` and `bpp.set_run_key_wrapper` is -replacing the default value `None` of the attribute `run` in each message generated within -the enclosed block with the user-defined run key. - -The `@bpp.set_run_key_decorator` and `bpp.set_run_key_wrapper` are primarily intended -to be applied to a function that contains a run implementation, but may be also used -with any block of plan code. For example, one may write a plan that simultaneously -opens multiple runs and executes them in parallel by generating groups of messages -with run ids of the open scans. This is currently not recommended and should be attempted -only at the developer's own risk. - -Plans with Sequential Runs ---------------------------- - -Sequential calling of multiple runs is supported by older versions of Bluesky. There is no need -to use multi-run plan features if runs are not overlapping (the next run is opened only after -the previous run is closed), but run keys still can be assigned to all or some runs if needed. - -In the following example, two preassembled plans are called in sequence. Run Engine is subscribed to -a single instance of BestEffortCallback, which is set up to display data specific for each run -when the run opened. - -.. literalinclude:: examples/multi_run_plans_sequential.py - -.. ipython:: python - :suppress: - - %run -m multi_run_plans_sequential - -.. ipython:: python - - RE(plan_sequential_runs(10)) - -Plans with Nested Runs ----------------------- - -The following example illustrates the use of `@bpp.set_run_key_decorator` to implement two nested runs: -the 'outer' run interrupts measurements, calls the 'inner' run and then completes the measurements. -The 'outer' and 'inner' runs are assigned different run ids ('run_1' and 'run_2'). Note that -the `@bpp.set_run_key_decorator` for the 'outer' run does not overwrite the run id of the 'inner' scan, -despite the fact that it is generated inside the enclosed code, since the decorator is designed to replace -the run id attribute of the message only if it has the default value of `None`, i.e. the run id of -a message can be replaced by the decorator only the first time it is processed by the decorator. - -If multiple runs are to be opened simultaneously, each run needs to be subscribed to its own instance -of callback. Standard RunEngine subscription mechanism does not provide this capability. Instead, -subscription should be performed via `RunRouter`. The code in the following example demonstrates how -to use `BestEffortCallback` to monitor data from multiple nested runs. - -.. literalinclude:: examples/multi_run_plans_nested.py - -The output of the plan contains data from two runs with each run assigned its own ID and UID. The tables -for the runs are printed by two separate instances of `BestEffortCallback`. The data from two tables -is printed in the order of acquisition: the table for the 'inner' run is printed in the gap of -the table for the 'outer' run. - -.. ipython:: python - :suppress: - - %run -m multi_run_plans_nested - -.. ipython:: python - - RE(sim_plan_outer(10)) - -The wrapper `bpp.set_run_key_wrapper` can be used instead of the decorator. For example -the run `sim_plan_inner` from the previous example can be rewritten as follows: - -.. code-block:: python - - def sim_plan_inner(npts): - def f(): - for j in range(npts): - yield from bps.mov(hw.motor1, j * 0.1 + 1, hw.motor2, j * 0.2 - 2) - yield from bps.trigger_and_read([hw.motor1, hw.motor2, hw.det2]) - f = bpp.run_wrapper(f(), md={}) - return bpp.set_run_key_wrapper(f, "run_2") - -Subscription to callbacks via RunRouter provides flexibility to subscribe each run -to its own set of callbacks. In the following example `run_key` is added to the start -document metadata and used to distinguish between two runs in the function factory that -performs callback subscriptions. - -.. literalinclude:: examples/multi_run_plans_select_cb.py - -.. ipython:: python - :suppress: - - %run -m multi_run_plans_select_cb - -.. ipython:: python - - RE(sim_plan_outer(10)) - -In some cases it may be necessary to implement a run that could be interrupted -and a new instance of the same run started. For example, the suspender pre- or post-plan -may contain a run, which takes substantial time to execute. Such run may be interrupted -if the suspender is repeatedly triggered. This will cause another instance of the pre- -or post-plan to be started while the first one is still in the open state. This process -is similar to recursive calling of the run (run which includes instructions to call -itself). Recursive calls are possible if unique run key is assigned to a run each -time it is started. - -The following example illustrates dynamic generation of run keys. The plan may have no practical purpose -besides demonstration of the principle. The plan is calling itself recursively multiple times until -the global counter `n_calls` reaches the maximum value of `n_calls_max`. The unique run key is generated -before at each call. - -.. literalinclude:: examples/multi_run_plans_recursive.py - -.. ipython:: python - :suppress: - - %run -m multi_run_plans_recursive - -.. ipython:: python - - RE(sim_plan_recursive(4)) - -The identical result can be achieved by using `bpp.set_run_key_wrapper()`: - -.. code-block:: python - - # Call counter and the maximum number calls - n_calls, n_calls_max = 0, 3 - - def sim_plan_recursive(npts): - global n_calls, n_calls_max - - n_calls += 1 # Increment counter - if n_calls <= n_calls_max: - # Generate unique key for each run. The key generation algorithm - # must only guarantee that execution of the runs that are assigned - # the same key will never overlap in time. - run_key = f"run_key_{n_calls}" - - @bpp.run_decorator(md={}) - def plan(npts): - - for j in range(int(npts/2)): - yield from bps.mov(hw.motor1, j * 0.2) - yield from bps.trigger_and_read([hw.motor1, hw.det1]) - - # Different parameter values may be passed to the recursively called plans - yield from sim_plan_recursive(npts + 2) - - for j in range(int(npts/2), npts): - yield from bps.mov(hw.motor1, j * 0.2) - yield from bps.trigger_and_read([hw.motor1, hw.det1]) - - yield from bpp.set_run_key_wrapper(plan(npts), run_key) diff --git a/bluesky/_sources/nsls2_checklist.txt b/bluesky/_sources/nsls2_checklist.txt deleted file mode 100644 index f89dcb5419..0000000000 --- a/bluesky/_sources/nsls2_checklist.txt +++ /dev/null @@ -1,11 +0,0 @@ -NSLS-II Beamline Configuration Checklist -======================================== - -The following are prerequisites for reliable data collection. - -* The clocks of all beamline computers should be synchronized to the "ring - clock." On UNIX machines, this is likely already done by the system - administrator. On Windows machines, this can be done in time settings. - The Network Time Protcol server (NTP server) is ``time.cs.nsls2.local``. - By default, syncing is not performed very often. It is best to configure - the settings so that syncing is performed every hour. diff --git a/bluesky/_sources/plans.rst.txt b/bluesky/_sources/plans.rst.txt deleted file mode 100644 index c988d2c31f..0000000000 --- a/bluesky/_sources/plans.rst.txt +++ /dev/null @@ -1,792 +0,0 @@ -.. currentmodule:: bluesky.plans - -===== -Plans -===== - -A *plan* is bluesky's concept of an experimental procedure. A plan may be any -iterable object (list, tuple, custom iterable class, ...) but most commonly it -is implemented as a Python generator. For a more technical discussion we refer -you :doc:`msg`. - -A variety of pre-assembled plans are provided. Like sandwiches on a deli menu, -you can use our pre-assembled plans or assemble your own from the same -ingredients, catalogued under the heading :ref:`stub_plans` below. - -.. note:: - - In the examples that follow, we will assume that you have a RunEngine - instance named ``RE``. This may have already been configured for you if you - are a user at a facility that runs bluesky. See - :ref:`this section of the tutorial ` to sort out - if you already have a RunEngine and to quickly make one if needed. - -.. _preassembled_plans: - -Pre-assembled Plans -=================== - -Below this summary table, we break the down the plans by category and show -examples with figures. - -Summary -------- - -Notice that the names in the left column are links to detailed API -documentation. - -.. autosummary:: - :toctree: generated - :nosignatures: - - count - scan - rel_scan - list_scan - rel_list_scan - list_grid_scan - rel_list_grid_scan - log_scan - rel_log_scan - grid_scan - rel_grid_scan - scan_nd - spiral - spiral_fermat - spiral_square - rel_spiral - rel_spiral_fermat - rel_spiral_square - adaptive_scan - rel_adaptive_scan - tune_centroid - tweak - ramp_plan - fly - - -Time series ("count") ---------------------- - -Examples: - -.. code-block:: python - - from ophyd.sim import det - from bluesky.plans import count - - # a single reading of the detector 'det' - RE(count([det])) - - # five consecutive readings - RE(count([det], num=5)) - - # five sequential readings separated by a 1-second delay - RE(count([det], num=5, delay=1)) - - # a variable delay - RE(count([det], num=5, delay=[1, 2, 3, 4])) - - # Take readings forever, until interrupted (e.g., with Ctrl+C) - RE(count([det], num=None)) - -.. code-block:: python - - # We'll use the 'noisy_det' example detector for a more interesting plot. - from ophyd.sim import noisy_det - - RE(count([noisy_det], num=5)) - - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import count - from ophyd.sim import noisy_det - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - RE = RunEngine({}) - RE.subscribe(bec) - RE(count([noisy_det], num=5)) - -.. note:: - - Why doesn't :func:`count` have an ``exposure_time`` parameter? - - Modern CCD detectors typically parametrize exposure time with *multiple* - parameters (acquire time, acquire period, num exposures, ...) as do scalers - (preset time, auto count time). There is no one "exposure time" that can be - applied to all detectors. - - Additionally, when using multiple detectors as in ``count([det1, det2]))``, - the user would need to provide a separate exposure time for each detector in - the general case, which would grow wordy. - - One option is to set the time-related parameter(s) as a separate step. - - For interactive use: - - .. code-block:: python - - # Just an example. Your detector might have different names or numbers of - # exposure-related parameters---which is the point. - det.exposure_time.set(3) - det.acquire_period.set(3.5) - - From a plan: - - .. code-block:: python - - # Just an example. Your detector might have different names or numbers of - # exposure-related parameters---which is the point. - yield from bluesky.plan_stubs.mv( - det.exposure_time, 3, - det.acquire_period, 3.5) - - Another is to write a custom plan that wraps :func:`count` and sets the - exposure time. This plan can encode the details that bluesky in general - can't know. - - .. code-block:: python - - def count_with_time(detectors, num, delay, exposure_time, *, md=None): - # Assume all detectors have one exposure time component called - # 'exposure_time' that fully specifies its exposure. - for detector in detectors: - yield from bluesky.plan_stubs.mv(detector.exposure_time, exposure_time) - yield from bluesky.plans.count(detectors, num, delay, md=md) - -.. autosummary:: - :toctree: generated - :nosignatures: - - count - -Scans over one dimension ------------------------- - -The "dimension" might be a physical motor position, a temperature, or a -pseudo-axis. It's all the same to the plans. Examples: - -.. code-block:: python - - from ophyd.sim import det, motor - from bluesky.plans import scan, rel_scan, list_scan - - # scan a motor from 1 to 5, taking 5 equally-spaced readings of 'det' - RE(scan([det], motor, 1, 5, 5)) - - # scan a motor from 1 to 5 *relative to its current position* - RE(rel_scan([det], motor, 1, 5, 5)) - - # scan a motor through a list of user-specified positions - RE(list_scan([det], motor, [1, 1, 2, 3, 5, 8])) - -.. code-block:: python - - RE(scan([det], motor, 1, 5, 5)) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import scan - from ophyd.sim import det, motor - RE = RunEngine({}) - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - RE.subscribe(bec) - RE(scan([det], motor, 1, 5, 5)) - -.. note:: - - Why don't scans have a ``delay`` parameter? - - You may have noticed that :func:`count` has a ``delay`` parameter but none - of the scans do. This is intentional. - - The common reason for wanting a delay in a scan is to allow a motor to - settle or a temperature controller to reach equilibrium. It is better to - configure this on the respective devices, so that scans will always add the - appropriate delay for the particular device being scanned. - - .. code-block:: python - - motor.settle_time = 1 - temperature_controller.settle_time = 10 - - For many cases, this is more convenient and more robust than typing a delay - parameter in every invocation of the scan. You only have to set it once, and - it applies thereafter. - - This is why bluesky leaves ``delay`` out of the scans, to guide users toward - an approach that will likely be a better fit than the one that might occur - to them first. For situations where a ``delay`` parameter really is the - right tool for the job, it is of course always possible to add a ``delay`` - parameter yourself by writing a custom plan. Here is one approach, using a - :ref:`per_step hook `. - - .. code-block:: python - - import bluesky.plans - import bluesky.plan_stubs - - def scan_with_delay(*args, delay=0, **kwargs): - "Accepts all the normal 'scan' parameters, plus an optional delay." - - def one_nd_step_with_delay(detectors, step, pos_cache): - "This is a copy of bluesky.plan_stubs.one_nd_step with a sleep added." - motors = step.keys() - yield from bluesky.plan_stubs.move_per_step(step, pos_cache) - yield from bluesky.plan_stubs.sleep(delay) - yield from bluesky.plan_stubs.trigger_and_read(list(detectors) + list(motors)) - - kwargs.setdefault('per_step', one_nd_step_with_delay) - yield from bluesky.plans.scan(*args, **kwargs) - -.. autosummary:: - :toctree: generated - :nosignatures: - - scan - rel_scan - list_scan - rel_list_scan - log_scan - rel_log_scan - -.. _multi-dimensional_scans: - -Multi-dimensional scans ------------------------ - -See :ref:`tutorial_multiple_motors` in the tutorial for an introduction to the -common cases of moving multiple motors in coordination (i.e. moving X and Y -along a diagonal) or in a grid. The key examples are reproduced here. Again, -see the section linked for further explanation. - -.. code-block:: python - - from ophyd.sim import det, motor1, motor2, motor3 - from bluesky.plans import scan, grid_scan, list_scan, list_grid_scan - - RE(scan(dets, - motor1, -1.5, 1.5, # scan motor1 from -1.5 to 1.5 - motor2, -0.1, 0.1, # ...while scanning motor2 from -0.1 to 0.1 - 11)) # ...both in 11 steps - - # Scan motor1 and motor2 jointly through a 5-point trajectory. - RE(list_scan(dets, motor1, [1, 1, 3, 5, 8], motor2, [25, 16, 9, 4, 1])) - - # Scan a 3 x 5 x 2 grid. - RE(grid_scan([det], - motor1, -1.5, 1.5, 3, # no snake parameter for first motor - motor2, -0.1, 0.1, 5, False)) - motor3, -200, 200, 5, False)) - - # Scan a grid with abitrary spacings given as specific positions. - RE(list_grid_scan([det], - motor1, [1, 1, 2, 3, 5], - motor2, [25, 16, 9])) - -All of these plans are built on a more general-purpose plan, -:func:`~bluesky.plan.scan_nd`, which we can use for more specialized cases. - -Some jargon: we speak of :func:`~bluesky.plans.scan`-like joint movement as an -"inner product" of trajectories and :func:`~bluesky.plans.grid_scan`-like -movement as an "outer product" of trajectories. The general case, moving some -motors together in an "inner product" against another motor (or motors) in an -"outer product," can be addressed using a ``cycler``. Notice what happens when -we add or multiply ``cycler`` objects. - -.. ipython:: python - - from cycler import cycler - from ophyd.sim import motor1, motor2, motor3 - - traj1 = cycler(motor1, [1, 2, 3]) - traj2 = cycler(motor2, [10, 20, 30]) - list(traj1) # a trajectory for motor1 - list(traj1 + traj2) # an "inner product" trajectory - list(traj1 * traj2) # an "outer product" trajectory - -We have reproduced inner product and outer product. The real power comes in -when we combine them, like so. Here, motor1 and motor2 together in a mesh -against motor3. - -.. ipython:: python - - traj3 = cycler(motor3, [100, 200, 300]) - list((traj1 + traj2) * traj3) - -For more on cycler, we refer you to the -`cycler documentation `_. To build a plan -incorporating these trajectories, use our general N-dimensional scan plan, -:func:`scan_nd`. - -.. code-block:: python - - RE(scan_nd([det], (traj1 + traj2) * traj3)) - -.. autosummary:: - :toctree: generated - :nosignatures: - - scan - rel_scan - grid_scan - rel_grid_scan - list_scan - rel_list_scan - list_grid_scan - rel_list_grid_scan - scan_nd - -Spiral trajectories -------------------- - -We provide two-dimensional scans that trace out spiral trajectories. - -A simple spiral: - -.. plot:: - :include-source: - - from bluesky.simulators import plot_raster_path - from ophyd.sim import motor1, motor2, det - from bluesky.plans import spiral - - plan = spiral([det], motor1, motor2, x_start=0.0, y_start=0.0, x_range=1., - y_range=1.0, dr=0.1, nth=10) - plot_raster_path(plan, 'motor1', 'motor2', probe_size=.01) - - -A fermat spiral: - -.. plot:: - :include-source: - - from bluesky.simulators import plot_raster_path - from ophyd.sim import motor1, motor2, det - from bluesky.plans import spiral_fermat - - plan = spiral_fermat([det], motor1, motor2, x_start=0.0, y_start=0.0, - x_range=2.0, y_range=2.0, dr=0.1, factor=2.0, tilt=0.0) - plot_raster_path(plan, 'motor1', 'motor2', probe_size=.01, lw=0.1) - - -A square spiral: - -.. plot:: - :include-source: - - from bluesky.simulators import plot_raster_path - from ophyd.sim import motor1, motor2, det - from bluesky.plans import spiral_square - - plan = spiral_square([det], motor1, motor2, x_center=0.0, y_center=0.0, - x_range=1.0, y_range=1.0, x_num=11, y_num=11) - plot_raster_path(plan, 'motor1', 'motor2', probe_size=.01) - - -.. autosummary:: - :toctree: generated - :nosignatures: - - spiral - spiral_fermat - spiral_square - rel_spiral - rel_spiral_fermat - rel_spiral_square - -Adaptive scans --------------- - -These are one-dimension scans with an adaptive step size tuned to move quickly -over flat regions can concentrate readings in areas of high variation by -computing the local slope aiming for a target delta y between consecutive -points. - -This is a basic example of the power of adaptive plan logic. - -.. code-block:: python - - from bluesky.plans import adaptive_scan - from ophyd.sim import motor, det - - RE(adaptive_scan([det], 'det', motor, - start=-15, - stop=10, - min_step=0.01, - max_step=5, - target_delta=.05, - backstep=True)) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import adaptive_scan - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - from ophyd.sim import motor, det - - RE = RunEngine({}) - RE.subscribe(bec) - - RE(adaptive_scan([det], 'det', motor, - start=-15.5, - stop=10, - min_step=0.01, - max_step=5, - target_delta=.05, - backstep=True)) - -From left to right, the scan lengthens its stride through the flat region. At -first, it steps past the peak. The large jump causes it to double back and then -sample more densely through the peak. As the peak flattens, it lengthens its -stride again. - -.. autosummary:: - :toctree: generated - :nosignatures: - - adaptive_scan - rel_adaptive_scan - -Misc. ------ - -.. autosummary:: - :toctree: generated - :nosignatures: - - tweak - fly - -.. _stub_plans: - -Stub Plans -========== -.. currentmodule:: bluesky.plan_stubs - -These are the aforementioned "ingredients" for remixing, the pieces from which -the pre-assembled plans above were made. See :ref:`tutorial_custom_plans` in -the tutorial for a practical introduction to these components. - -Plans for interacting with hardware: - -.. autosummary:: - :nosignatures: - :toctree: generated - - abs_set - rel_set - mv - mvr - trigger - read - rd - stage - unstage - configure - stop - -Plans for asynchronous acquisition: - -.. autosummary:: - :nosignatures: - :toctree: generated - - monitor - unmonitor - kickoff - complete - collect - -Plans that control the RunEngine: - -.. autosummary:: - :nosignatures: - :toctree: generated - - open_run - close_run - create - save - drop - pause - deferred_pause - checkpoint - clear_checkpoint - sleep - input_plan - subscribe - unsubscribe - install_suspender - remove_suspender - wait - wait_for - null - -Combinations of the above that are often convenient: - -.. autosummary:: - :toctree: generated - - trigger_and_read - one_1d_step - one_nd_step - one_shot - move_per_step - -Special utilities: - -.. autosummary:: - :toctree: generated - - repeat - repeater - caching_repeater - broadcast_msg - -.. _preprocessors: - -Plan Preprocessors -================== -.. currentmodule:: bluesky.preprocessors - -.. _supplemental_data: - -Supplemental Data ------------------ - -Plan preprocessors modify a plans contents on the fly. One common use of a -preprocessor is to take "baseline" readings of a group of devices at the -beginning and end of each run. It is convenient to apply this to *all* plans -executed by a RunEngine using the :class:`SupplementalData`. - -.. autoclass:: SupplementalData - :members: - -We have installed a "preprocessor" on the RunEngine. A preprocessor modifies -plans, supplementing or altering their instructions in some way. From now on, -every time we type ``RE(some_plan())``, the RunEngine will silently change -``some_plan()`` to ``sd(some_plan())``, where ``sd`` may insert some extra -instructions. Envision the instructions flow from ``some_plan`` to ``sd`` and -finally to ``RE``. The ``sd`` preprocessors has the opportunity to inspect -he -instructions as they go by and modify them as it sees fit before they get -processed by the RunEngine. - -Preprocessor Wrappers and Decorators ------------------------------------- - -Preprocessors can make arbirary modifcations to a plan, and can get quite -devious. For example, the :func:`relative_set_wrapper` rewrites all positions -to be relative to the initial position. - -.. code-block:: python - - def rel_scan(detectors, motor, start, stop, num): - absolute = scan(detectors, motor, start, stop, num) - relative = relative_set_wrapper(absolute, [motor]) - yield from relative - -This is a subtle but remarkably powerful feature. - -Wrappers like :func:`relative_set_wrapper` operate on a generator *instance*, -like ``scan(...)``. There are corresponding decorator functions like -``relative_set_decorator`` that operate on a generator -*function* itself, like :func:`scan`. - -.. code-block:: python - - # Using a decorator to modify a generator function - def rel_scan(detectors, motor, start, stop, num): - - @relative_set_decorator([motor]) # unfamiliar syntax? -- see box below - def inner_relative_scan(): - yield from scan(detectors, motor, start, stop, num) - - yield from inner_relative_scan() - -Incidentally, the name ``inner_relative_scan`` is just an internal variable, -so why did we choose such a verbose name? Why not just name it ``f``? That -would work, of course, but using a descriptive name can make debugging easier. -When navigating gnarly, deeply nested tracebacks, it helps if internal variables -have clear names. - -.. note:: - - The decorator syntax --- the ``@`` --- is a succinct way of passing a - function to another function. - - This: - - .. code-block:: python - - @g - def f(...): - pass - - f(...) - - is equivalent to - - .. code-block:: python - - g(f)(...) - -Built-in Preprocessors ----------------------- -.. currentmodule:: bluesky.preprocessors - -Each of the following functions named ``_wrapper`` operates on -a generator instance. The corresponding functions named -```` operate on a generator function. - -.. autosummary:: - :nosignatures: - :toctree: generated - - baseline_decorator - baseline_wrapper - contingency_wrapper - finalize_decorator - finalize_wrapper - fly_during_decorator - fly_during_wrapper - inject_md_decorator - inject_md_wrapper - lazily_stage_decorator - lazily_stage_wrapper - monitor_during_decorator - monitor_during_wrapper - relative_set_decorator - relative_set_wrapper - reset_positions_decorator - reset_positions_wrapper - run_decorator - run_wrapper - stage_decorator - stage_wrapper - subs_decorator - subs_wrapper - suspend_decorator - suspend_wrapper - -Custom Preprocessors --------------------- - -The preprocessors are implemented using :func:`msg_mutator` (for altering -messages in place) and :func:`plan_mutator` (for inserting -messages into the plan or removing messages). - -It's easiest to learn this by example, studying the implementations of the built-in -processors (catalogued above) in the -`the source of the plans module `_. - -.. _per_step_hook: - -Customize Step Scans with ``per_step`` -====================================== - -The one-dimensional and multi-dimensional plans are composed (1) setup, -(2) a loop over a plan to perform at each position, (3) cleanup. - -We provide a hook for customizing step (2). This enables you to write a -variation of an existing plan without starting from scratch. - -For one-dimensional plans, the default inner loop is: - -.. code-block:: python - - from bluesky.plan_stubs import checkpoint, abs_set, trigger_and_read - - def one_1d_step(detectors, motor, step): - """ - Inner loop of a 1D step scan - - This is the default function for ``per_step`` param in 1D plans. - """ - yield from checkpoint() - yield from abs_set(motor, step, wait=True) - return (yield from trigger_and_read(list(detectors) + [motor])) - -Some user-defined function, ``custom_step``, with the same signature can be -used in its place: - -.. code-block:: python - - scan([det], motor, 1, 5, 5, per_step=custom_step) - -For convenience, this could be wrapped into the definition of a new plan: - -.. code-block:: python - - def custom_scan(detectors, motor, start, stop, step, *, md=None): - yield from scan([det], motor, start, stop, step, md=md - per_step=custom_step) - -For multi-dimensional plans, the default inner loop is: - -.. code-block:: python - - from bluesky.utils import short_uid - from bluesky.plan_stubs import checkpoint, abs_set, wait, trigger_and_read - - def one_nd_step(detectors, step, pos_cache): - """ - Inner loop of an N-dimensional step scan - - This is the default function for ``per_step`` param in ND plans. - - Parameters - ---------- - detectors : iterable - devices to read - step : dict - mapping motors to positions in this step - pos_cache : dict - mapping motors to their last-set positions - """ - def move(): - yield from checkpoint() - grp = short_uid('set') - for motor, pos in step.items(): - if pos == pos_cache[motor]: - # This step does not move this motor. - continue - yield from abs_set(motor, pos, group=grp) - pos_cache[motor] = pos - yield from wait(group=grp) - - motors = step.keys() - yield from move() - yield from trigger_and_read(list(detectors) + list(motors)) - -Likewise, a custom function with the same signature may be passed into the -``per_step`` argument of any of the multi-dimensional plans. - -Asynchronous Plans: "Fly Scans" and "Monitoring" -================================================ - -See the section on :doc:`async` for some context on these terms and, near the -end of the section, some example plans. - -.. _plan_utils: - -Plan Utilities -============== - -These are useful utilities for defining custom plans and plan preprocessors. - -.. autosummary:: - :toctree: generated - :nosignatures: - - pchain - msg_mutator - plan_mutator - single_gen - make_decorator diff --git a/bluesky/_sources/plans.txt b/bluesky/_sources/plans.txt deleted file mode 100644 index ac0e755247..0000000000 --- a/bluesky/_sources/plans.txt +++ /dev/null @@ -1,1408 +0,0 @@ -.. currentmodule:: bluesky.plans - -Plans -===== - -A *plan* is bluesky's concept of an experimental procedure. A -:doc:`previous section ` introduced some built-in plans like -:func:`count`, :func:`scan`, and :func:`relative_scan`. This section covers all -of the plans and plan-related tools in bluesky with examples showing how to -combine and customize them. - -A variety of pre-assembled plans are provided. Like sandwiches on a deli menu, -you can use our pre-assembled plans or assemble your own from the same -ingredients, catalogued under the heading :ref:`stub_plans` below. - -Built-in Plans --------------- - -.. _preassembled_plans: - -Pre-assembled Plans -+++++++++++++++++++ - -Below this summary table, we break the down the plans by category and show -examples with figures. - -Summary -^^^^^^^ - -Notice that the names in the left column are links to detailed API -documentation. - -.. autosummary:: - :toctree: - :nosignatures: - - count - scan - relative_scan - list_scan - relative_list_scan - log_scan - relative_log_scan - inner_product_scan - outer_product_scan - relative_inner_product_scan - relative_outer_product_scan - scan_nd - spiral - spiral_fermat - relative_spiral - relative_spiral_fermat - adaptive_scan - relative_adaptive_scan - tweak - fly - -Time series ("count") -^^^^^^^^^^^^^^^^^^^^^ - -Examples: - -.. code-block:: python - - from bluesky.examples import det - from bluesky.plans import count - - # a single reading of the detector 'det' - RE(count([det])) - - # five consecutive readings - RE(count([det], num=5)) - - # five sequential readings separated by a 1-second delay - RE(count([det], num=5, delay=1)) - - # a variable delay - RE(count([det], num=5, delay=[1, 2, 3, 4]) - - # Take readings forever, until interrupted (e.g., with Ctrl+C) - RE(count([det], num=None)) - -We can use ``LivePlot`` to visualize this data. It is documented in the -:ref:`next section `. - -.. code-block:: python - - from bluesky.callbacks import LivePlot - - # We'll use the 'noisy_det' example detector for a more interesting plot. - from bluesky.examples import noisy_det - - RE(count([noisy_det], num=5), LivePlot('noisy_det')) - - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import count - from bluesky.examples import noisy_det - from bluesky.callbacks import LivePlot - RE = RunEngine({}) - RE(count([noisy_det], num=5), LivePlot('noisy_det')) - -.. autosummary:: - :toctree: - :nosignatures: - - count - -Scans over one dimesion -^^^^^^^^^^^^^^^^^^^^^^^ - -The "dimension" might be a physical motor position, a temperature, or a -pseudo-axis. It's all the same to the plans. Examples: - -.. code-block:: python - - from bluesky.examples import det, motor - from bluesky.plans import scan, relative_scan, list_scan - - # scan a motor from 1 to 5, taking 5 equally-spaced readings of 'det' - RE(scan([det], motor, 1, 5, 5)) - - # scan a motor from 1 to 5 *relative to its current position* - RE(relative_scan([det], motor, 1, 5, 5)) - - # scan a motor through a list of user-specified positions - RE(list_scan([det], motor, [1, 1, 2, 3, 5, 8])) - -Again, we can use ``LivePlot`` to visualize this data. It is documented in the -:ref:`next section `. - -.. code-block:: python - - from bluesky.callbacks import LivePlot - - RE(scan([det], motor, 1, 5, 5), LivePlot('det', 'motor')) - -Or, again, to save some typing for repeated use, -:ref:`define a custom plan with the plot incorporated `. -(LivePlot itself is documented :ref:`here `.) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import scan - from bluesky.examples import det, motor - from bluesky.callbacks import LivePlot - RE = RunEngine({}) - RE(scan([det], motor, 1, 5, 5), LivePlot('det', 'motor')) - -.. autosummary:: - :toctree: - :nosignatures: - - scan - relative_scan - list_scan - relative_list_scan - log_scan - relative_log_scan - -.. _multi-dimensional_scans: - -Multi-dimensional scans -^^^^^^^^^^^^^^^^^^^^^^^ - -Here, "dimensions" are things independently scanned. They may be physical -position (stepping motor), temperature, etc. - -We introduce jargon for two different kinds of a multi-dimensional -(multi-"motor") scan. Moving motors together in a joint trajectory is an "inner -product scan." This is like moving an object along a diagonal by moving the x -and y motors simultaneously. - -.. code-block:: python - - from bluesky.examples import det, motor1, motor2 - from bluesky.plans import inner_product_scan - - # Inner product: move motors together. - # Move motor1 from 1-5 while moving motor2 from 10-50 -- both in 5 steps. - RE(inner_product_scan([det], 5, motor1, 1, 5, motor2, 10, 50)) - -Demo: - -.. ipython:: python - :suppress: - - from bluesky.examples import det, motor1, motor2 - from bluesky.callbacks import LiveTable - from bluesky import RunEngine - from bluesky.plans import outer_product_scan, inner_product_scan - RE = RunEngine({}) - -.. ipython:: python - - RE(inner_product_scan([det], 5, motor1, 1, 5, motor2, 10, 50), - LiveTable(['det', 'motor1', 'motor2'])) - -.. plot:: - - from bluesky.plan_tools import plot_raster_path - from bluesky.examples import motor1, motor2, det - from bluesky.plans import inner_product_scan - import matplotlib.pyplot as plt - - plan = inner_product_scan([det], 5, motor1, 1, 5, motor2, 10, 50) - plot_raster_path(plan, 'motor1', 'motor2', probe_size=.3) - -Notice that, in an inner product scan, each motor moves the same number -of steps (in the example above, 5). - -Moving motors separately, exploring every combination, is an "outer product -scan". This is like moving x and y to draw a mesh. The mesh does not have to be -square: each motor can move a different number of steps. - -.. code-block:: python - - from bluesky.examples import det, motor1, motor2 - from bluesky.plans import outer_product_scan - - # Outer product: move motors in a mesh. - # Move motor1 from 1-3 in 3 steps and motor2 from 10-50 in 5 steps. - RE(outer_product_scan([det], motor1, 1, 3, 3, motor2, 10, 50, 5, False)) - -Demo: - -.. ipython:: python - - RE(outer_product_scan([det], motor1, 1, 3, 3, motor2, 10, 50, 5, False), - LiveTable(['det', 'motor1', 'motor2'])) - -The final parameter designates whether motor2 should "snake" back and forth -along motor1's trajectory (``True``) or retread its positions in the same -direction each time (``False``), as illustrated. - -.. plot:: - - from bluesky.plan_tools import plot_raster_path - from bluesky.examples import motor1, motor2, det - from bluesky.plans import outer_product_scan - import matplotlib.pyplot as plt - - true_plan = outer_product_scan([det], motor1, -5, 5, 10, motor2, -7, 7, 15, True) - false_plan = outer_product_scan([det], motor1, -5, 5, 10, motor2, -7, 7, 15, False) - - fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True) - plot_raster_path(true_plan, 'motor1', 'motor2', probe_size=.3, ax=ax1) - plot_raster_path(false_plan, 'motor1', 'motor2', probe_size=.3, ax=ax2) - ax1.set_title('True') - ax2.set_title('False') - ax1.set_xlim(-6, 6) - ax2.set_xlim(-6, 6) - -Both :func:`inner_product_scan` and :func:`outer_product_scan` support an -unlimited number of motors/dimensions. - -To visualize 2-dimensional data, we can use ``LiveRaster``, which is documented -in :ref:`in the next section `. In previous examples we used -``LivePlot`` to visualize readings as a function of one variable; -``LiveRaster`` is appropriate for functions of two variables. - -.. code-block:: python - - from bluesky.callbacks import LiveRaster - - # The 'det4' example detector a 2D Gaussian function of motor1, motor2. - from bluesky.examples import det4 - - RE(outer_product_scan([det4], motor1, -3, 3, 6, motor2, -5, 5, 10, False), - LiveRaster((6, 10), 'det4')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import outer_product_scan - from bluesky.examples import det4, motor1, motor2 - from bluesky.callbacks import LiveRaster - motor1._fake_sleep = 0 - motor2._fake_sleep = 0 - RE = RunEngine({}) - RE(outer_product_scan([det4], motor1, -3, 3, 6, motor2, -5, 5, 10, False), - LiveRaster((6, 10), 'det4')) - -The general case, moving some motors together in an "inner product" against -another (or motors) in an "outer product," can be addressed using a ``cycler``. -Notice what happens when we add or multiply ``cycler`` objects. - -.. ipython:: python - - from cycler import cycler - from bluesky.examples import motor1, motor2, motor3 - - traj1 = cycler(motor1, [1, 2, 3]) - traj2 = cycler(motor2, [10, 20, 30]) - list(traj1) # a trajectory for motor1 - list(traj1 + traj2) # an "inner product" trajectory - list(traj1 * traj2) # an "outer product" trajectory - -We have reproduced inner product and outer product. The real power comes in -when we combine them, like so. Here, motor1 and motor2 together in a mesh -against motor3. - -.. ipython:: python - - traj3 = cycler(motor3, [100, 200, 300]) - list((traj1 + traj2) * traj3) - -For more on cycler, we refer you to the -`cycler documentation `_. To build a plan -incorporating these trajectories, use our general N-dimensional scan plan, -:func:`scan_nd`. - -.. code-block:: python - - RE(scan_nd([det], (traj1 + traj2) * traj3)) - -.. autosummary:: - :toctree: - :nosignatures: - - inner_product_scan - outer_product_scan - relative_inner_product_scan - relative_outer_product_scan - scan_nd - -Spiral trajectories -^^^^^^^^^^^^^^^^^^^ - -We provide two-dimensional scans that trace out spiral trajectories. - -A simple spiral: - -.. plot:: - :include-source: - - from bluesky.plan_tools import plot_raster_path - from bluesky.examples import motor1, motor2, det - from bluesky.plans import spiral - - plan = spiral([det], motor1, motor2, x_start=0.0, y_start=0.0, x_range=1., - y_range=1.0, dr=0.1, nth=10) - plot_raster_path(plan, 'motor1', 'motor2', probe_size=.01) - - -A fermat spiral: - -.. plot:: - :include-source: - - from bluesky.plan_tools import plot_raster_path - from bluesky.examples import motor1, motor2, det - from bluesky.plans import spiral_fermat - - plan = spiral_fermat([det], motor1, motor2, x_start=0.0, y_start=0.0, - x_range=2.0, y_range=2.0, dr=0.1, factor=2.0, tilt=0.0) - plot_raster_path(plan, 'motor1', 'motor2', probe_size=.01, lw=0.1) - - -.. autosummary:: - :toctree: - :nosignatures: - - spiral - spiral_fermat - relative_spiral - relative_spiral_fermat - -Adaptive scans -^^^^^^^^^^^^^^ - -These are one-dimension scans with an adaptive step size tuned to move quickly -over flat regions can concentrate readings in areas of high variation by -computing the local slope aiming for a target delta y between consecutive -points. - -This is a basic example of the power of adaptive plan logic. - -.. code-block:: python - - from bluesky.plans import adaptive_scan - from bluesky.callbacks import LivePlot - from bluesky.examples import motor, det - - RE(adaptive_scan([det], 'det', motor, - start=-15, - stop=10, - min_step=0.01, - max_step=5, - target_delta=.05, - backstep=True), - LivePlot('det', 'motor', markersize=10, marker='o')) - -.. plot:: - - from bluesky import RunEngine - from bluesky.plans import adaptive_scan - from bluesky.callbacks import LivePlot - from bluesky.examples import motor, det - - RE = RunEngine({}) - - RE(adaptive_scan([det], 'det', motor, - start=-15, - stop=10, - min_step=0.01, - max_step=5, - target_delta=.05, - backstep=True), - LivePlot('det', 'motor', markersize=10, marker='o')) - -From left to right, the scan lengthens its stride through the flat region. At -first, it steps past the peak. The large jump causes it to double back and then -sample more densely through the peak. As the peak flattens, it lengthens its -stride again. - -.. autosummary:: - :toctree: - :nosignatures: - - adaptive_scan - relative_adaptive_scan - -Misc. -^^^^^ - -.. autosummary:: - :toctree: - :nosignatures: - - tweak - fly - -.. _stub_plans: - -Stub Plans -++++++++++ - -These are the aforementioned "ingredients" for remixing, the pieces from which -the pre-assembled plans above were made. The next section provides many -examples. - -Plans for interacting with hardware: - -.. autosummary:: - :nosignatures: - :toctree: - - abs_set - rel_set - mv - trigger - read - stage - unstage - configure - stop - -Plans for asynchronous acquisition: - -.. autosummary:: - :nosignatures: - :toctree: - - monitor - unmonitor - kickoff - complete - collect - -Plans that control the RunEngine: - -.. autosummary:: - :nosignatures: - :toctree: - - open_run - close_run - create - save - pause - deferred_pause - checkpoint - clear_checkpoint - sleep - subscribe - unsubscribe - wait - wait_for - null - -Combinations of the above that are often convenient: - -.. autosummary:: - trigger_and_read - one_1d_step - one_nd_step - -We also provide :ref:`wrapper and decorator functions ` and -:ref:`utility functions `, documented below, that make building -these easier. - - -.. _plan_examples1: - -Examples --------- - -Changing a Parameter Between Runs -+++++++++++++++++++++++++++++++++ - -Produce several runs, changing a parameter each time. - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.examples import det, motor - - def scan_varying_density(): - "Run a scan several times, changing the step size each time." - for num in range(5, 10): - # Scan motor from -1 to 1, sampling more densely in each - # iteration. - yield from scan([det], motor, -1, 1, num) - -Setting Devices to a Set Point -++++++++++++++++++++++++++++++ - -Next, we introduce :func:`abs_set`, which sets a motor to a position (or a -temperature controller to a temperature, etc.). See also :func:`rel_set`, which -sets *relative* to the current value. - -.. code-block:: python - - from bluesky.plans import count, abs_set - from bluesky.examples import det, motor - - def move_and_count(): - "Move a motor into place, then take a reading from detectors." - yield from abs_set(motor, 3, wait=True) - yield from count([det]) - -The argument ``wait=True`` blocks progress until the device reports that it is -ready (e.g., done moving or done triggering). Alternatively, use a :func:`wait` -plan, which is more flexible. Here, we move two motors at once and wait for -them both to finish. - -.. code-block:: python - - from bluesky.plans import abs_set, wait - from bluesky.examples import motor1, motor2 - - def set_two_motors(): - "Set, trigger, read" - yield from abs_set(motor1, 5, group='A') # Start moving motor1. - yield from abs_set(motor2, 5, group='A') # Start moving motor2. - yield from wait('A') # Now wait for both to finish. - -The ``group`` is just temporary label that we can use to refer to groups of -devices that we want to move or trigger simulataneously and then wait for them -as a group. This plan will continue once both motors have reported that they -have finished moving successfully. - -We could have written this some logic with a loop: - -.. code-block:: python - - def set_multiple_motors(motors): - "Set all motors moving; then wait for all motors to finish." - for motor in motors: - yield from abs_set(motor, 5, group='A') - yield from wait('A') - -Two convenient shortcuts are available for common cases. As shown at the -beginning of this section, if you are setting one motor at a time, use the -``wait`` keyword argument. - -.. code-block:: python - - def set_one_motor(): - yield from abs_set(motor1, wait=True) - # `wait=True` implicitly adds a group and `wait` plan to match. - -The same works for :func:`rel_set` and :func:`trigger`. Also, if you are only -dealing with one group at a time, you do not actually need to label the group: - -.. code-block:: python - - def set_multiple_motors(motors): - "Set all motors moving; then wait for all motors to finish." - for motor in motors: - yield from abs_set(motor, 5) - yield from wait() - -But by using labels you can express complex logic, waiting for different groups -at different points in the plan: - -.. code-block:: python - - def staggered_wait(det, fast_motors, slow_motor): - # Start all the motors, fast and slow, moving at once. - # Put all the fast_motors in one group... - for motor in fast_motors: - yield from abs_set(motor, 5, group='A') - # ...but put the slow motor is separate group. - yield from abs_set(slow_motor, 5, group='B') - - # Wait for all the fast motors. - yield from wait('A') - - # Do some stuff that doesn't require the slow motor to be finished. - - # Then wait for the slow motor. - yield from wait('B') - -Before writing a custom plan to coordinate the motion of multiple devices, -consider whether your use case could be addressed with one of the built-in -:ref:`multi-dimensional_scans`. - -Sleeping -++++++++ - -A "sleep" is a timed delay. - -.. code-block:: python - - from bluesky.plans import sleep, abs_set - from bluesky.examples import motor - - def sleepy(): - "Set motor; sleep for a fixed time; set it to a new position." - yield from abs_set(motor, 5) - yield from sleep(2) # units: seconds - yield from abs_set(motor, 10) - -The :func:`sleep` plan is not the same as Python's built-in sleep function, -``time.sleep(...)``. Never use ``time.sleep(...)`` in a plan; use ``yield from -sleep(...)`` instead. It allows other tasks --- such as watching for Ctrl+C, -updating plots --- to be executed while the clock runs. - -.. _planned_pauses: - -Planned Pauses -++++++++++++++ - -Pausing is typically done :ref:`interactively ` (Ctrl+C) -but it can also be incorporated into a plan. The plan can pause the RunEngine, -requiring the user to type ``RE.resume()`` to continue or ``RE.stop()`` to -clean up and stop. - -Pauses can be interspersed using :func:`chain`. Demo: - -.. ipython:: python - - from bluesky.plans import pchain, count, pause - from bluesky.examples import det - RE(pchain(count([det]), pause(), count([det]))) - RE.state # optional -- just doing this to show that we are paused - RE.resume() # or, alternatively, RE.stop() - -Or pauses can be incorporated in a plan like so: - -.. code-block:: python - - from bluesky.plans import pause, checkpoint - - def pausing_plan(): - while True: - yield from some_plan(...) - print("Type RE.resume() to go again or RE.stop() to stop.") - yield from checkpoint() # marking where to resume from - yield from pause() - -.. _customizing_metadata: - -Customizing metadata --------------------- - -Metadata can be loaded from a persistent file, specified by the user -interactively at execution time, or incorporated in a plan. - -All of the pre-assembled plans also accept an ``md`` ("metadata") argument, -which makes it easy for a user-defined plan to pass in extra metadata. - -.. code-block:: python - - from bluesky.plans import count - from bluesky.examples import det - - def master_plan(): - "Read a detector with the shutter closed and then open." - # ... insert code here to close shutter ... - yield from count([det], md={'is_dark_frame': True}) - # ... insert code here to open shutter ... - yield from count([det], md={'is_dark_frame': False}) - -By default, the :func:`count` plan records ``{'plan_name': 'count'}``. To -customize the ``plan_name`` --- say, to differentiate separate *reasons* for -running a count --- you can override this behavior. - -.. code-block:: python - - def calib_count(dets, num=3): - "A count whose data will be designated 'calibration'." - md = {'plan_name': 'calib_count'} - yield from count(dets, num=num, md=md) - -The above records the ``{'plan_name': 'calib_count'}``. To enable users to -pass in metadata that combines with and potentially overrides the hard-coded -metadata, use the following pattern: - -.. code-block:: python - - from collections import ChainMap - - def calib_count(dets, num=3, *, md=None): - "A count whose data will be designated 'calibration'." - if md is None: - md = {} - md = ChainMap(md, - {'plan_name': 'calib_count'}) - yield from count(dets, num=num, md=md) - -For example, if the plan is called with the arguments: - -.. code-block:: python - - calib_count([det], md={'plan_name': 'watermelon'}) - -then ``'watermelon'`` will override ``'calib_count'`` as the recorded plan -name. - -.. note:: - - The built-in Python data structure ``ChainMap`` is a sequence of - dictionaries (a "chain of mappings"). It gives priority to the first - mapping that defines a given key. - - .. ipython:: python :suppress: - - from collections import ChainMap - - .. ipython:: python - - m = ChainMap({'a': 1}, {'a': 2, 'b': 3}) - m['a'] - m['b'] - - Thus, ``a=1`` takes precedence of ``a=2``. We use it to give user-provided - metadata precedence over a plan's hard-coded metadata in the event of a - key collision. - - See the `relevant section of the Python documentation `_ - for more. - -.. _preprocessors: - -Plan Preprocessors ------------------- - -These "preprocessors" take in a plan and modify its contents on the fly. For -example, :func:`relative_set_wrapper` rewrites all positions to be relative to -the initial position. - -.. code-block:: python - - def relative_scan(detectors, motor, start, stop, num): - absolute = scan(detectors, motor, start, stop, num) - relative = relative_set_wrapper(absolute, [motor]) - yield from relative - -This is a subtle but remarkably powerful feature. - -Wrappers like :func:`relative_set_wrapper` operate on a generator *instance*, -like ``scan(...)``. There are corresponding decorator functions like -``relative_set_decorator`` that operate on a generator -*function* itself, like :func:`scan`. - -.. code-block:: python - - # Using a decorator to modify a generator function - def relative_scan(detectors, motor, start, stop, num): - - @relative_set_decorator([motor]) # unfamiliar syntax? -- see box below - def inner_relative_scan(): - yield from scan(detectors, motor, start, stop, num) - - yield from inner_relative_scan() - -Incidentally, the name ``inner_relative_scan`` is just an internal variable, -so why did we choose such a verbose name? Why not just name it ``f``? That -would work, of course, but using a descriptive name can make debugging easier. -When navigating gnarly, deeply nested tracebacks, it helps if internal variables -have clear names. - -.. note:: - - The decorator syntax --- the ``@`` --- is a succinct way of passing a - function to another function. - - This: - - .. code-block:: python - - @g - def f(...): - pass - - f(...) - - is equivalent to - - .. code-block:: python - - g(f)(...) - -Built-in Preprocessors -++++++++++++++++++++++ - -Each of the following functions named ``_wrapper`` operates on -a generator instance. The corresponding functions named -```` operate on a generator function. - -.. autosummary:: - :nosignatures: - :toctree: - - baseline_decorator - baseline_wrapper - finalize_decorator - finalize_wrapper - fly_during_decorator - fly_during_wrapper - inject_md_decorator - inject_md_wrapper - lazily_stage_decorator - lazily_stage_wrapper - monitor_during_decorator - monitor_during_wrapper - relative_set_decorator - relative_set_wrapper - reset_positions_decorator - reset_positions_wrapper - run_decorator - run_wrapper - stage_decorator - stage_wrapper - subs_decorator - subs_wrapper - -Custom Preprocessors -++++++++++++++++++++ - -The preprocessors are implemented using :func:`msg_mutator` (for altering -messages in place) and :func:`plan_mutator` (for inserting -messages into the plan or removing messages). - -It's easiest to learn this by example, studying the implementations of the built-in -processors (catalogued above) in the -`the source of the plans module `_. - -.. _exception_handling: - -How Plans Handle Exceptions ---------------------------- - -If an exception is raised, the RunEngine gives the plan the opportunity to -catch the exception and either handle it or merely yield some "clean up" -messsages before re-raising the exception and killing plan execution. - -The exception in question may originate from the plan itself or from the -RunEngine when it attempts to execute a given command. - -.. code-block:: python - - # This example is illustrative, but it is not completely correct. - # Use `finalize_wrapper` instead (or read its source code). - - def plan_with_cleanup(): - try: - yield from main_plan() - except Exception: - # Catch the exception long enough to clean up. - yield from cleanup_plan() - raise # Re-raise the exception. - -The :func:`finalize_wrapper` preprocessor provides a succinct and fully correct -way of applying this general pattern. - -.. code-block:: python - - from bluesky.plans import finalize_wrapper - - def plan_with_cleanup(): - yield from finalize_wrapper(main_plan(), cleanup_plan()) - -Or, at your preference, the same logic is available as a decorator: - -.. code-block:: python - - from bluesky.plans import finalize_decorator - - plan_with_cleanup = finalize_decorator(cleanup_plan)(main_plan) - - # or, equivalently: - - @finalize_decorator(cleanup_plan) - def plan_with_cleanup(): - yield from main_plan() - -Customize Step Scans with ``per_step`` --------------------------------------- - -The one-dimensional and multi-dimensional plans are composed (1) setup, -(2) a loop over a plan to perform at each position, (3) cleanup. - -We provide a hook for customizing step (2). This enables you to write a -variation of an existing plan without starting from scratch. - -For one-dimensional plans, the default inner loop is: - -.. code-block:: python - - from bluesky.plans import checkpoint, abs_set, trigger_and_read - - def one_1d_step(detectors, motor, step): - """ - Inner loop of a 1D step scan - - This is the default function for ``per_step`` param in 1D plans. - """ - yield from checkpoint() - yield from abs_set(motor, step, wait=True) - return (yield from trigger_and_read(list(detectors) + [motor])) - -Some user-defined function, ``custom_step``, with the same signature can be -used in its place: - -.. code-block:: python - - scan([det], motor, 1, 5, 5, per_step=custom_step) - -For convenience, this could be wrapped into the definition of a new plan: - -.. code-block:: python - - def custom_scan(detectors, motor, start, stop, step, *, md=None): - yield from scan([det], motor, start, stop, step, md=md - per_step=custom_step) - -For multi-dimensional plans, the default inner loop is: - -.. code-block:: python - - from bluesky.utils import short_uid - from bluesky.plans import checkpoint, abs_set, wait, trigger_and_read - - def one_nd_step(detectors, step, pos_cache): - """ - Inner loop of an N-dimensional step scan - - This is the default function for ``per_step`` param in ND plans. - - Parameters - ---------- - detectors : iterable - devices to read - step : dict - mapping motors to positions in this step - pos_cache : dict - mapping motors to their last-set positions - """ - def move(): - yield from checkpoint() - grp = short_uid('set') - for motor, pos in step.items(): - if pos == pos_cache[motor]: - # This step does not move this motor. - continue - yield from abs_set(motor, pos, group=grp) - pos_cache[motor] = pos - yield from wait(group=grp) - - motors = step.keys() - yield from move() - yield from trigger_and_read(list(detectors) + list(motors)) - -Likewise, a custom function with the same signature may be passed into the -``per_step`` argument of any of the multi-dimensional plans. - -.. _reimplementing_count: - -Controlling the Scope of a "Run" --------------------------------- - -By default, the :func:`count` plan generates one "run" (i.e., dataset) -with one "event" (i.e., one bundle of readings from the detectors, one row in -a table of the data). - -.. code-block:: python - - from bluesky.examples import det1, det2 - from bluesky.plans import count - - dets = [det1, det2] - RE(count(dets)) - -The ``num`` argument enables multiple events (rows) in one run. - -.. code-block:: python - - # one 'run' with three 'events' - RE(count(dets, num=3)) - -If we didn't provide a num option, how could you make one yourself? - -A tempting --- but wrong! --- possibility is to loop over calls to -``RE(count(dets))``. - -.. code-block:: python - - # Don't do this! - for _ in range(3): - RE(count(dets)) - -As stated earlier, this ruins error-recovery and interruption recovery. It's -much better to do the loop inside a custom plan, which we'll dub -``multicount``. - -.. code-block:: python - - def multicount(dets): - for _ in range(3): - yield from count(dets) - - RE(multicount(dets)) - -In fact, instead of hard-coding 3, we could make it an argument configurable -by the user. We can make the configuration optional by providing 3 as a -default. - -.. code-block:: python - - def multicount(dets, num=3): - for _ in range(num): - yield from count(dets) - -But this still creates three runs --- three datasets --- for what we'd rather -think of as three events (rows) in one run. To fix that, we'll have to dive -deeper, re-implementing :func:`count` from scratch. - -.. code-block:: python - - from bluesky.plans import run_decorator, stage_decorator, trigger_and_read - - def multicount(dets, num=3, *, md=None): - - @stage_decorator(dets) - @run_decorator(md=md) - def inner_multicount(): - for _ in range(num): - yield from trigger_and_read(dets) - - yield from inner_multicount() - - -Starting from the middle and explaining outward: - -* The :func:`trigger_and_read` plan generates an "event" (a row of data) from - reading ``dets``. This happens inside of a loop, ``num`` times. -* The :func:`run_decorator` preprocessor designates the scope of one run. -* The :func:`stage_decorator` preprocessor addresses some hardware details. It - primes the hardware for data collection. For some devices, this has no - effect at all. But for others, it ensures that the device is put into a - ready, triggerable state and then restored to standby at the end of the plan. - -Plans with Adaptive Logic -------------------------- - -Two-way communication is possible between the generator and the RunEngine. -For example, the 'read' command responds with its reading. We can use it to -make an on-the-fly decision about whether to continue or stop. - -.. code-block:: python - - from bluesky.plans import abs_set, trigger, read - from bluesky.examples import det, motor - - def conditional_break(threshold): - """Set, trigger, read until the detector reads intensity < threshold""" - i = 0 - while True: - print("LOOP %d" % i) - yield from abs_set(motor, i) - yield from trigger(det, wait=True) - reading = yield from read(det) - if reading['det']['value'] < threshold: - print('DONE') - break - i += 1 - -Demo: - -.. code-block:: python - - In [5]: RE(conditional_break(0.2)) - LOOP 0 - LOOP 1 - LOOP 2 - DONE - Out[5]: [] - -The important line in this example is - -.. code-block:: python - - reading = yield from read(det) - -The action proceeds like this: - -1. The plan yields a 'read' message to the RunEngine. -2. The RunEngine reads the detector. -3. The RunEngine sends that reading *back to the plan*, and that response is - assigned to the variable ``reading``. - -The response, ``reading``, is formatted like: - -.. code-block:: python - - {: {'value': , 'timestamp': }, ...} - -For a detailed technical description of the messages and their responses, -see :ref:`msg`. - -Asynchronous Plans: "Fly Scans" and "Monitoring" ------------------------------------------------- - -See the section on :doc:`async` for some context on these terms and, near the -end of the section, some example plans. - -.. _plan_utils: - -Plan Utilities --------------- - -These are useful utilities for defining custom plans and plan preprocessors. - -.. autosummary:: - :toctree: - :nosignatures: - - pchain - msg_mutator - plan_mutator - single_gen - broadcast_msg - repeater - caching_repeater - make_decorator - -Object-Oriented-Style Plans ---------------------------- - -These provide an alternative interface to plans that is convenient for some -workflows. The plan becomes a reusable object: unlike a generator instance, it -is not "exhausted" after the first use. - -.. code-block:: python - - from bluesky.plans import Scan - from bluesky.examples import motor, det, det3 - plan = Scan([det], motor, 1, 3, 3) # a "reusable" object-oriented plan - -When it is passed to the RunEngine (in general, when it is iterated over) it -re-instantiates a generator automatically using the same parameters. - -.. code-block:: python - - RE(plan) # This is the same as before... - RE(plan) # ...but this would not work with generators, only the OO plans. - -For each parameter there is an attribute that can be adjusted interactively. - -.. code-block:: python - - plan.num = 4 # change number of data points from 10 to 4 - plan.detectors.append(det3) # add another detector - -The ``set`` method is a convenient way to update multiple parameters at once. - -.. code-block:: python - - plan.set(start=20, stop=25) - -Built-in Object-Oriented Plans -++++++++++++++++++++++++++++++ - -For each of the "pre-assembled" plans catalogued above, bluesky ships an -object-oriented counterpart. - -.. autosummary:: - :nosignatures: - :toctree: - - Count - Scan - RelativeScan - ListScan - RelativeListScan - LogScan - RelativeLogScan - InnerProductScan - OuterProductScan - RelativeInnerProductScan - RelativeOuterProductScan - ScanND - SpiralScan - SpiralFermatScan - RelativeSpiralScan - RelativeSpiralFermatScan - AdaptiveScan - RelativeAdaptiveScan - Tweak - -Custom Object-Oriented Plans -++++++++++++++++++++++++++++ - -To define a custom object-oriented Plan, follow this pattern. Here we define -:class:`Scan`, the object-oriented counterpart to :func:`scan`. - -.. code-block:: python - - from bluesky.plans import Plan - - class Scan(Plan): - __doc__ = scan.__doc__ # mirror the docstring of 'scan' - - def __init__(self, detectors, motor, start, stop, num, *, md=None): - self.detectors = detectors - self.motor = motor - self.start = start - self.stop = stop - self.num = num - self.md = md - - def _gen(self): - return scan(self.detectors, self.motor, self.start, self.stop, - self.num, md=self.md) - - -This ``__init__`` method contains a lot of boilerplate code, assigning an -attribute for each argument. For cases like this where a plan takes zero or -more required arguments plus ``md``, the ``Plan`` class provides a shortcut -using metaclass magic. - -Optionally, the definition of ``__init__`` can be entirely removed and replaced -by the line - -.. code-block:: python - - _fields = ['detectors', 'motor', 'start', 'stop', 'num'] - -which ``Plan`` uses to auto-generate an ``__init__`` at class definition time. -If that is a little too "magical" for your taste, feel free to skip it and just -write out the ``__init__`` method, as we did in the example above. - -.. _spec_api: - -SPEC-like API with Global State -------------------------------- - -Some scientists are familiar with `SPEC `_, -a domain-specific language for hardware control. It is possible to imitate the -SPEC workflow on top of bluesky. Of course, we still adhere to the Python -syntax so that we can employ the full power of the general-purpose Python -language. - -The "SPEC-like" plans are extensions of the pre-assembled plans, reusing the -same internal logic under a different interface. - -Built-in SPEC-like plans -++++++++++++++++++++++++ - -.. currentmodule:: bluesky - -.. autosummary:: - :toctree: - :nosignatures: - - spec_api.ct - spec_api.ascan - spec_api.dscan - spec_api.mesh - spec_api.a2scan - spec_api.d2scan - spec_api.a3scan - spec_api.d3scan - spec_api.spiral - spec_api.aspiral - spec_api.fermat - spec_api.afermat - spec_api.tw - spec_api.th2th - -Differences from non-SPEC-like plans -++++++++++++++++++++++++++++++++++++ - -To see the differences, compare the SPEC-like plan ``ascan`` its non-SPEC-like -counterpart :func:`scan`. - -.. code-block:: python - - # non-SPEC-like - RE(scan([det], motor, 1, 5, 5)) - - # SPEC-like - gs.DETS = [det] - RE(ascan(motor, 1, 5, 4)) - -* **Global list of detectors.** :func:`scan` expects a list of detectors --- e.g., - ``[det]`` --- as its first argument. ``ascan`` obtains the detector list - implicitly by checking the current value of ``gs.DETS``. -* **Globally configured subscriptions.** ``ascan`` bakes in subscriptions to - ``LiveTable`` and ``LivePlot`` by default. These defaults are configurable - --- see below. -* **Arguments' names and ordering.** The signatures match those in the SPEC - manual. In some cases they are different from the signature of their non-SPEC - counterparts, which adhere more closely to idiomatic scientific Python. - What :func:`scan` calls "start" and "stop" ``ascan`` calls "start" and "finish". -* **Count strides, not points.** Following the convention in SPEC, the - SPEC-like plans expect the number of "intervals" (strides) N, leading to N + - 1 points. In all other parts of bluesky, we adhere to the Python/scipy - convention, expecting the user to input the number of points. To avoid - ambiguity, the argument names are different: non-SPEC-like plans have a - ``num`` argument; SPEC-like plans have ``intervals`` instead. - -Global state -++++++++++++ - -Bluesky ships ``bluesky.global_state.gs``, a singleton ``GlobalState`` object -that serves as a stash for configuration shared by the SPEC-like plans. - -In IPython, type ``gs??`` for an exhuastive list of its attributes. Highlights: - -======================= ======= -Attribute Purpose -======================= ======= -``gs.DETS`` the list of detectors -``gs.TABLE_COLS`` list of field names to include in ``LiveTable`` -``gs.PLOT_Y`` field name to plot as y axis of ``LivePlot`` -``gs.OVERPLOT`` True or False; whether to replot to same axes -``gs.FLYERS`` "flyable" devices to fly-scan during all plans -``gs.MONITORS`` devices to monitor asynchronously during all plans -``gs.BASELINE_DEVICES`` devices to read once before and after all plans -======================= ======= - -For more context about what "flyers" and "monitors" mean, see the section on -:doc:`async`. - -Subscription Factories -++++++++++++++++++++++ - -Another important attribute of global state is ``gs.SUB_FACTORIES``, which -requires some explaining. This feature is related to bluesky's subscriptions -model for processing data. If you are unfamiliar, you should skim -:ref:`callbacks` before proceeding. - -``SUB_FACTORIES`` stands for "subscription factories." Each entry in the -``SUB_FACTORIES`` dictionary maps a ``plan_name`` (e.g., ``'ascan'``) to -functions that return callback functions. These callbacks will be subscribed to -documents generated by that plan. Example: - -.. code-block:: python - - from bluesky.global_state import gs - from bluesky.callbacks import LiveTable - - def setup_livetable(*, motors, gs): - "Construct a LiveTable callback based on the motors and gs." - return LiveTable(motors + [gs.PLOT_Y] + gs.TABLE_COLS) - - gs.SUB_FACTORIES['ascan'] = [setup_livetable] - -The function can expect as arguments ``gs`` and any metadata generated by the -plan --- in the example above, the list of motors. The function's signature is -inspected automatically, and it is magically passed the correct parameters. - -The leading ``*`` in the function signature makes ``motors`` and ``gs`` -*required, keyword-only arguments*. Any custom functions must follow this -pattern as well in order for the magic inspection to work properly. - -Built-in Subscription Factories -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. currentmodule:: bluesky - -.. autosummary:: - :toctree: - :nosignatures: - - spec_api.setup_plot - spec_api.setup_ct_plot - spec_api.setup_livetable - spec_api.setup_peakstats - spec_api.setup_liveraster diff --git a/bluesky/_sources/plans_intro.txt b/bluesky/_sources/plans_intro.txt deleted file mode 100644 index 3f19d2f77e..0000000000 --- a/bluesky/_sources/plans_intro.txt +++ /dev/null @@ -1,334 +0,0 @@ -.. currentmodule:: bluesky.plans - -Basic Usage & Intro to Plans -============================ - -Key Components --------------- - -A *plan* is bluesky's concept of an experimental procedure, a sequence of -instructions to execute. Some common examples follow; many more are in a -:doc:`later section `. In Python jargon, a plan can be any iterable. It -could be a simple list or a generator, a concept which is addressed in detail -below. - -Each granular instruction in a plan is dubbed a *message*. - -The *RunEngine* is a kind of interpreter for plans. It executes the messages -in the plan, controlling hardware while monitoring for interruptions, collating -metadata and data, coordinating I/O, and ensuring that the hardware is left in -a safe state at exit time. - -First Step: Creating a RunEngine --------------------------------- - -This document is addressing two different audiences, and we have different -setup instructions for each. - -* If you are a user at NSLS-II taking real data, do nothing. You already - have a RunEngine defined as the variable ``RE`` by your IPython profile, - and it is configured to save data. - -* To just play around --- either for educational purposes or to test out an - experiment before saving any data, start a new IPython session and - define a RunEngine. - - .. code-block:: python - - from bluesky import RunEngine - RE = RunEngine({}) - - An "out-of-the-box" RunEngine is not configured to save any data! - Close IPython when you are done, lest someone accidentally try to take - real data with your "toy" RunEngine. - -Running the RunEngine ---------------------- - -We'll use the built-in :func:`scan` plan, which moves a motor and triggers and -reads one or more detectors. We'll pass the plan to the RunEngine for -execution. - -.. ipython:: python - :suppress: - - from bluesky import RunEngine - RE = RunEngine({}) - -.. ipython:: python - - from bluesky.plans import scan - from bluesky.examples import motor, det # a simulated motor and detector - RE(scan([det], motor, 1, 5, 5)) # Scan from 1 to 5 in 5 steps. - -The plan has been executed. But where is the data? The RunEngine must be given -instructions to do anything with the data. For example, to print a table during -the scan, we'll send the data to ``LiveTable``, which formats some data and -metadata generated by this plan into a table. - -.. ipython:: python - - from bluesky.callbacks import LiveTable - RE(scan([det], motor, 1, 5, 5), LiveTable([det, motor])) - -Or, similarly, we can plot the data during the scan using ``LivePlot``. - -.. ipython:: python - - from bluesky.callbacks import LivePlot - RE(scan([det], motor, 1, 5, 5), LivePlot('det', 'motor')) - -.. plot:: - - from bluesky import RunEngine - RE = RunEngine({}) - from bluesky.plans import scan - from bluesky.examples import motor, det - from bluesky.callbacks import LivePlot - RE(scan([det], motor, 1, 5, 5), LivePlot('det', 'motor')) - -To save typing, bluesky provides more succinct ways to include tables, plots, -and more --- read on. - -But, to summarize, the above syntax shows all of the pieces. The RunEngine -``RE`` consumes the messages from the plan ``scan([det], motor, 1, 5, 5)`` and -sends the data to ``LiveTable([det, motor])``, which then displays the time, -sequence number, and readings from ``det`` and ``motor`` in real time. - -.. note:: - - Why ``[det]`` and not just ``det``? It is common to read a *list* of - detectors as a group, like ``[det1, det2]``. - -The return value is a unique identifier for the data set(s) generated by the -plan. These can be used to retrieve the data later. - -Introspecting Plans -------------------- - -Bluesky's design separates the *specification* of the plan --- e.g., -``count([det])`` --- from the *execution* of the plan --- ``RE(count([det]))`` ---- lets us inspect the plan before running it. It also let us modify a plan on -the fly, as we'll see :ref:`later below `. - -Bluesky provides a simple function for summarizing the action of a plan, -``print_summary``. Here, we see that the plan :func:`count` opens a "run" (i.e., -dataset), takes a reading, and marks the end of that run. - -.. ipython:: python - - from bluesky.plan_tools import print_summary - from bluesky.examples import det - from bluesky.plans import count - print_summary(count([det])) - -The plan :func:`scan` moves a motor in steps and takes a reading at each -position. - -.. ipython:: python - - from bluesky.examples import motor, det - from bluesky.plans import scan, relative_scan - print_summary(scan([det], motor, 1, 3, 3)) - -.. ipython:: python - :suppress: - - motor.set(3) - -As you might guess, :func:`relative_scan` moves the motor relative to its -starting position. And at the end, :func:`relative_scan` returns it to that -starting position. - -.. ipython:: python - - print_summary(relative_scan([det], motor, 1, 3, 3)) - -Summarizing a plan is also a quick way to check for some types of errors. -More sophisticated error checking is possible and a likely area of future -development in bluesky. - - -.. note:: - - As the name suggests, ``print_summary`` omits some details. To examine the - full content of a plan, just pass it to ``list()``. - - This will not work on plans that are adaptive. Adaptive plans necessarily - generate their messages on the fly. - -Another useful application is visualization of motor trajectories. For example, -``plot_raster_path`` visualizes the trajectory of a two-motor system. The probe -size, given in "data space" units, provides a sense of this trajectory's -coverage of the sample. - -.. note:: - - In IPython, before running examples that generate plots, you may need to - first run :ref:`some setup commands ` if they were not already run - by startup scripts. - -.. plot:: - :include-source: - - from bluesky.plan_tools import plot_raster_path - from bluesky.examples import motor1, motor2, det - from bluesky.plans import outer_product_scan - import matplotlib.pyplot as plt - - plan = outer_product_scan([det], motor1, -5, 5, 10, motor2, -7, 7, 15, True) - plot_raster_path(plan, 'motor1', 'motor2', probe_size=.3) - -A Primer on ``yield`` and ``yield from`` ----------------------------------------- - -This is a very brief primer on the Python syntax ``yield`` and ``yield from``, -a feature of the core language that we will use extensively. - -A Python *function* returns once: - -.. ipython:: python - - def f(): - return 1 - - f() - -A Python *generator* is like a function with multiple exit points. Calling a -generator produces an *iterator* that yields one value at a time. After -each ``yield`` statement, its execution is suspended. - -.. ipython:: python - - def f(): - yield 1 - yield 2 - -We can exhaust the generator (i.e., get all its values) by calling ``list()``. - -.. ipython:: python - - list(f()) - -We can get one value at a time by calling ``next()`` - -.. ipython:: python - - it = f() - next(it) - next(it) - -or by looping through the values. - -.. ipython:: python - - for val in f(): - print(val) - -To examine what is happening when, we can add prints. - -.. ipython:: python - - def verbose_f(): - print("before 1") - yield 1 - print("before 2") - yield 2 - -.. ipython:: python - - it = verbose_f() - next(it) - next(it) - -Notice that execution is suspended after the first yield statement. The -second ``print`` is not run until we resume execution by requesting a second -value. This is a useful feature of generators: they can express "lazy" -execution. - -Generators can delegate to other generators using ``yield from``. This is -syntax we commonly use to combine plans. - -.. ipython:: python - - def double_f(): - yield from f() - yield from f() - -The above is equivalent to: - -.. ipython:: python - - def double_f(): - for val in f(): - yield val - for val in f(): - yield val - -The ``yield from`` syntax is just more succinct. - -.. ipython:: python - - list(double_f()) - -Combining Plans ---------------- - -You might be tempted to write a script like this: - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.examples import motor, det - - # Don't do this! - for j in [1, 2, 3]: - print(j, 'steps') - RE(scan([det], motor, 5, 10, j))) - -Or a function like this: - -.. code-block:: python - - # Don't do this! - def my_function(): - for j in [1, 2, 3]: - print(j, 'steps') - RE(scan([det], motor, 5, 10, j))) - - -But, instead, you should do this: - -.. code-block:: python - - from bluesky.plans import scan - from bluesky.examples import motor, det - - def my_plan(): - for j in [1, 2, 3]: - print(j, 'steps') - yield from scan([det], motor, 5, 10, j) - - RE(my_plan()) - -Why? Calling ``RE(...)`` inside a script or function means that you can not use -any of the introspection tools on it. Also, in the event of an error or -interruption, repeated calls to ``RE`` break the RunEngine's ability to -smoothly recover, and they can easily result in unintended behavior. To avoid -these problems, always express a multi-step procedure as a single plan (as -above) and pass the whole thing to ``RE``. - -A convenient way to run multiple plans in sequence is :func:`pchain` (for "plan -chain"): - -.. code-block:: python - - from bluesky.examples import motor, det - from bluesky.plans import scan, sleep, pchain - - RE(pchain(scan([det], motor, 1, 5, 3), - sleep(1), - scan([det], motor, 5, 10, 2))) - -Many more examples of built-in and custom plans follow in the section on -:doc:`plans`. diff --git a/bluesky/_sources/progress-bar.rst.txt b/bluesky/_sources/progress-bar.rst.txt deleted file mode 100644 index 6d3e681e58..0000000000 --- a/bluesky/_sources/progress-bar.rst.txt +++ /dev/null @@ -1,56 +0,0 @@ -Progress Bar -************ - -Bluesky provides a progress bar add-on. For example, two motors moving -simulateously make a display like this: - -.. code-block:: none - - mtr1 9%|███▊ | 0.09/1.0 [00:00<00:01, 1.21s/deg] - mtr2100%|████████████████████████████████████████████| 1.0/1.0 [00:01<00:00, 1.12s/deg] - -This display includes: - -* the name of the device (motor, temperature controller, etc.) -* the distance (or degrees, etc.) traveled so far -* the total distance to be covered -* the time elapsed -* the estimated time remaining -* the rate (determined empirically) - -The progress bar relies on the device to report its progress. If a device does -not provide comprehensive information, a simpler progress bar will be shown, -listing the names of devices being waited on and reporting which have -completed. - -.. code-block:: none - - mtr1 [No progress bar available.] - mtr2 [Complete.] - -Any time the RunEngine waits on hardware the progress bar is notified. This -includes, for example, waiting for a motor to move or waiting for a detector to -trigger. (In bluesky jargon, the progress bar is notified any time the -RunEngine processes a 'wait' command). - -The progress bar is not set up by default. It must be attached to a RunEngine. -This need only be done once (say, in a startup file). - -.. code-block:: python - - from bluesky.utils import ProgressBarManager - - RE.waiting_hook = ProgressBarManager() - -Some motions are very quick and not worth displaying a progress bar for. By -default, a progress bar is only drawn after 0.2 seconds. If an action completes -before then, the progress bar is never shown. To choose a shorter or longer -delay---say 5 seconds---use the parameter ``ProgressBarManager(delay_draw=5)``. - -For more technical detail about communication between the device, the -RunEngine, and the ProgressBarManager, read about the ``watch`` method in the -:ref:`status_obj_api` and ``waiting_hook`` in the :doc:`run_engine_api`. - -The implementation of the progress bar itself makes use of -`tqdm `_, a lovely Python package for making -a progress bar out of any iterable. diff --git a/bluesky/_sources/run_engine.rst.txt b/bluesky/_sources/run_engine.rst.txt deleted file mode 100644 index 102fa3cd9a..0000000000 --- a/bluesky/_sources/run_engine.rst.txt +++ /dev/null @@ -1,791 +0,0 @@ -The RunEngine run loop -====================== - -*Note: This is a technical document not optimized for user readability.* - -In this document, we start with a simplified version of the bluesky RunEngine. -We add more complexity step by step, with commentary. - -The heart of bluesky is the ``RunEngine._run`` co-routine which dispatches the -``Msg`` in the plan to functions that actually carry out the requested task. -The core operation is obscured by the layers of exception handling, state -management, and clean up the RunEngine is responsible for. (Some of this may -be refactored in the near future). This document is only going to discuss the -run loop, not Document generation or hardware clean up. - -Minimal RunEngine ------------------ - -A minimal (run-able) RunEngine is - -.. code:: python - - from time import sleep - import datetime - now = datetime.datetime.now - from bluesky import Msg - - function_map = {'print': - lambda msg: print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)), - 'sleep': - lambda msg: sleep(msg.args[0])} - - - def RE_v0(plan): - for msg in plan: - func = function_map[msg.command] - func(msg) - - welcome_plan = [Msg('print', 'hello'), Msg('sleep', None, 1), Msg('print', 'world!')] - - RE_v0(welcome_plan) - -which captures one of the key abstractions of bluesky: A plan is -just an iterable of messages. This abstraction means that the to plan an -experiment you only need to generate a stream of ``Msg`` objects and the -RunEngine will take care of actually executing the code. - -Adaptive Plans --------------- - -Simply having a stream of commands is not quite enough, you may want to -have the code generating the stream of messages be aware of the return -value of a previous ``Msg`` to decide what to do next. This sort of -thing is supported in python using -`generators `__ -which 'suspend' their execution at a ``yield`` statement. When you -iterate over a generator, it runs until the next ``yield`` -statement, suspends, and yields the value to the code which is iterating -over it. - -Switching to generators requires we change our minimal RE to - -.. code:: python - - from bluesky.utils import ensure_generator - - - - def RE_v1(plan): - plan = ensure_generator(plan) - last_result = None - - while True: - try: - msg = plan.send(last_result) - except StopIteration: - # generators indicate they are done by raising - # StopIteration - break - func = function_map[msg.command] - last_result = func(msg) - - -which still works with the ``welcome_plan`` - -.. code:: python - - RE_v1([Msg('print', 'hello'), Msg('sleep', None, 1), Msg('print', 'world!')]) - -but we can also do more sophisticated things like - -.. code:: python - - function_map['sum'] = lambda msg: sum(msg.args) - - def adding_plan(a, b): - yield Msg('print', '{} + {} = ??'.format(a, b)) - ret = yield Msg('sum', None, a, b) - yield Msg('print', '{} + {} = {}'.format(a, b, ret)) - yield Msg('print', 'thanks for adding') - -Which gives - -.. code:: python - - RE_v1(adding_plan(1, 2)) - RE_v1(adding_plan(5, 2)) - -This is obviously overkill for simple addition, but enables this like an -adaptive dscan that changes the step size based on the local slope. - -Exception Handling ------------------- - -In addition to ``generator.send`` (which inserts a value into the -generator) you can also use ``generator.throw`` which raises an -exception at the point where the generator is paused. If the generator -handles the exception (via a ``try...except`` block) then generator -runs until the next ``yield`` and ``throw`` returns the yielded -value. If the generator does not handle the exception (or raises a -different exception) then it is (re)raised by ``throw``. - -We want to be able to capture any exceptions raised by the ``RE`` -and pass those back to the plan. - -.. code:: python - - - def RE_v2(plan): - plan = ensure_generator(plan) - last_result = None - _exception = None - while True: - try: - if _exception is not None: - msg = plan.throw(_exception) - _exception = None - else: - msg = plan.send(last_result) - - except StopIteration: - break - try: - func = function_map[msg.command] - last_result = func(msg) - except Exception as e: - _exception = e - - -We can now write plans that handle exception from the RE, in this case -reporting that the addition failed due to a ``TypeError`` - -.. code:: python - - def safe_adding_plan(a, b): - yield Msg('print', '{} + {} = ??'.format(a, b)) - try: - ret = yield Msg('sum', None, a, b) - except TypeError: - yield Msg('print', 'can not add {} + {}!'.format(a, b)) - else: - yield Msg('print', '{} + {} = {}'.format(a, b, ret)) - finally: - yield Msg('print', 'thanks for adding') - -Compare the behavior of between ``adding_plan`` and ``addingplan`` in cases -where they succeed - -.. code:: python - - RE_v2(safe_adding_plan(1, 2)) - RE_v2(adding_plan(1, 2)) - -and fail - -.. code:: python - - RE_v2(safe_adding_plan('a', 2)) - RE_v2(adding_plan('a', 2)) - -Again, this is overkill for these simple cases, but this mechanism -allows us to write delta scans that always return the motors to their -original position, shut shutters, etc even if the plan fails or is -canceled. - -Turn into a callable class --------------------------- - -We are going to want to have access to the internal state of the -``_run`` loop very soon. An way to do this, while maintaining -the API we have above is to write a callable class instead of a -function. - -.. code:: python - - class RunEngine_v3: - def _sleep(self, msg): - sleep(msg.args[0]) - - def _print(self, msg): - print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)), - - def _sum(self, msg): - return sum(msg.args) - - def __init__(self): - self._command_registry = { - 'print': self._print, - 'sum': self._sum, - 'sleep': self._sleep} - - def __call__(self, plan): - self._run(plan) - - def _run(self, plan): - plan = ensure_generator(plan) - last_result = None - _exception = None - while True: - try: - if _exception is not None: - msg = plan.throw(_exception) - _exception = None - else: - msg = plan.send(last_result) - - except StopIteration: - break - try: - func = self._command_registry[msg.command] - last_result = func(msg) - except Exception as e: - _exception = e - - - RE_v3 = RunEngine_v3() - -In doing this we also pulled the function the commands dispatched to -into the class. While these methods are almost trivial, we will soon -have methods that alter the internal state of the ``RunEngine``. - -``asyncio`` integration ------------------------ - -So far all of these RE implementations have been synchronous functions, -that is they run straight through the plan. However, at a beamline we -need to be able to support asynchronous functionality and gracefully -interrupt the plan. - -To enable this we are using ``asyncio`` from the python standard library -(new in 3.4) to provide the outer event loop. At this point we are -integrating together two event loops: the RE loop which is processing -the plan and the ``asyncio`` event loop which is managing multiple -frames of execution. The event loop may switch between execution frames -when a coroutine is suspended by a ``yield from`` statement. Thus we -change the methods we dispatch to and the main ``_run`` method to -co-routines by adding the ``@asyncio.coroutine`` decorator and calling -the dispatched functions via ``yield from`` rather than with a direct -function call. - -We also added a ``msg_hook`` attribute to the ``RunEngine`` -which is a super handy debugging tool to see exactly what messages are -being processed by the RunEngine. It can be set to any callable which -takes a single ``Msg`` as input (ex ``print``) - -.. code:: python - - import asyncio - - - class RunEngine_v4: - def __init__(self, *, loop=None): - # map messages to coro - self._command_registry = { - 'print': self._print, - 'sum': self._sum, - 'sleep': self._sleep} - - # debugging hook - self.msg_hook = None - - - # bind RE to a specific loop - if loop is None: - loop = asyncio.get_event_loop() - self.loop = loop - - # The RunEngine keeps track of a *lot* of state. - # All flags and caches are defined here with a comment. Good luck. - self._task = None # asyncio.Task associated with call to self._run - - def __call__(self, plan): - self._task = self.loop.create_task(self._run(plan)) - self.loop.run_until_complete(self._task) - - if self._task.done() and not self._task.cancelled(): - exc = self._task.exception() - if exc is not None: - raise exc - - @asyncio.coroutine - def _run(self, plan): - plan = ensure_generator(plan) - last_result = None - _exception = None - while True: - try: - yield from asyncio.sleep(0.0001, loop=self.loop) - if _exception is not None: - msg = plan.throw(_exception) - _exception = None - else: - msg = plan.send(last_result) - - except StopIteration: - break - - if self.msg_hook: - self.msg_hook(msg) - - try: - func = self._command_registry[msg.command] - last_result = yield from func(msg) - except Exception as e: - _exception = e - - @asyncio.coroutine - def _sleep(self, msg): - yield from asyncio.sleep(msg.args[0]) - - @asyncio.coroutine - def _print(self, msg): - print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)), - - @asyncio.coroutine - def _sum(self, msg): - return sum(msg.args) - - - - RE_v4 = RunEngine_v4() - -Pausing, Resuming, and Rewinding --------------------------------- - -Adding the ability to pause/resume/rewind a scan adds a fair amount of -complexity as now the ``RunEngine`` must keep track of a stack of plans -rather than a single plan, cache ``Msg`` as they go by and expose enough -API to control the behavior. - -.. code:: python - - from collections import deque - import asyncio - - import datetime - import functools - from bluesky.utils import (AsyncInput, FailedPause, InvalidCommand, Msg, - ensure_generator) - from bluesky.run_engine import RunEngineStateMachine, PropertyMachine - from super_state_machine.errors import TransitionError - - - class RunEngine_v5: - state = PropertyMachine(RunEngineStateMachine) - _UNCACHEABLE_COMMANDS = ['pause', ] - - def __init__(self, *, loop=None): - # map messages to coro - self._command_registry = { - 'print': self._print, - 'sum': self._sum, - # coros on real RE - 'sleep': self._sleep, - 'checkpoint': self._checkpoint, - 'clear_checkpoint': self._clear_checkpoint, - 'rewindable': self._rewindable, - 'pause': self._pause, - 'input': self._input, - 'null': self._null, } - - # debugging hook - self.msg_hook = None - - # bind RE to a specific loop - if loop is None: - loop = asyncio.get_event_loop() - self.loop = loop - - # The RunEngine keeps track of a *lot* of state. - # All flags and caches are defined here with a comment. Good luck. - self._task = None # asyncio.Task associated with call to self._run - - self._deferred_pause_requested = False # pause at next 'checkpoint' - self._msg_cache = deque() # history of processed msgs for rewinding - self._rewindable_flag = True # if the RE is allowed to replay msgs - self._plan = None # the scan plan instance from __call__ - self._plan_stack = deque() # stack of generators to work off of - self._response_stack = deque([None]) # resps to send into the plans - self._interrupted = False # True if paused, aborted, or failed - - def __call__(self, plan): - # First thing's first: if we are in the wrong state, raise. - if not self.state.is_idle: - raise RuntimeError("The RunEngine is in a %s state" % self.state) - - self._clear_call_cache() - - self._plan = plan - gen = ensure_generator(plan) - - self._plan_stack.append(gen) - self._response_stack.append(None) - - self._task = self.loop.create_task(self._run()) - self.loop.run_forever() - - if self._task.done() and not self._task.cancelled(): - exc = self._task.exception() - if exc is not None: - raise exc - - def _clear_call_cache(self): - self._deferred_pause_requested = False - self._plan_stack = deque() - self._msg_cache = deque() - self._response_stack = deque([None]) - self._exception = None - self._task = None - self._plan = None - self._interrupted = False - - @property - def rewindable(self): - return self._rewindable_flag - - @rewindable.setter - def rewindable(self, v): - cur_state = self._rewindable_flag - self._rewindable_flag = bool(v) - if self.resumable and self._rewindable_flag != cur_state: - self._reset_checkpoint_state() - - @property - def resumable(self): - "i.e., can the plan in progress by rewound" - return self._msg_cache is not None - - @asyncio.coroutine - def _run(self): - pending_cancel_exception = None - try: - self.state = 'running' - while True: - try: - yield from asyncio.sleep(0.0001, loop=self.loop) - # The case where we have a stashed exception - if self._exception is not None: - # throw the exception at the current plan - try: - msg = self._plan_stack[-1].throw( - self._exception) - except Exception as e: - # The current plan did not handle it, - # maybe the next plan (if any) would like - # to try - self._plan_stack.pop() - if len(self._plan_stack): - self._exception = e - continue - # no plans left and still an unhandled exception - # re-raise to exit the infinite loop - else: - raise - # clear the stashed exception, the top plan - # handled it. - else: - self._exception = None - # The normal case of clean operation - else: - resp = self._response_stack.pop() - try: - msg = self._plan_stack[-1].send(resp) - # We have exhausted the top generator - except StopIteration: - # pop the dead generator go back to the top - self._plan_stack.pop() - if len(self._plan_stack): - continue - # or reraise to get out of the infinite loop - else: - raise - # Any other exception that comes out of the plan - except Exception as e: - # pop the dead plan, stash the exception and - # go to the top of the loop - self._plan_stack.pop() - if len(self._plan_stack): - self._exception = e - continue - # or reraise to get out of the infinite loop - else: - raise - - if self.msg_hook: - self.msg_hook(msg) - - # if this message can be cached for rewinding, cache it - if (self._msg_cache is not None and - self._rewindable_flag and - msg.command not in self._UNCACHEABLE_COMMANDS): - # We have a checkpoint. - self._msg_cache.append(msg) - - # try to look up the coroutine to execute the command - try: - coro = self._command_registry[msg.command] - # replace KeyError with a local sub-class and go - # to top of the loop - except KeyError: - # TODO make this smarter - self._exception = InvalidCommand(msg.command) - continue - - # try to finally run the command the user asked for - try: - # this is one of two places that 'async' - # exceptions (coming in via throw) can be - # raised - response = yield from coro(msg) - # special case `CancelledError` and let the outer - # exception block deal with it. - except asyncio.CancelledError: - raise - # any other exception, stash it and go to the top of loop - except Exception as e: - self._exception = e - continue - # normal use, if it runs cleanly, stash the response and - # go to the top of the loop - else: - self._response_stack.append(response) - continue - - except KeyboardInterrupt: - # This only happens if some external code captures SIGINT - # -- overriding the RunEngine -- and then raises instead - # of (properly) calling the RunEngine's handler. - # See https://github.com/NSLS-II/bluesky/pull/242 - print("An unknown external library has improperly raised " - "KeyboardInterrupt. Intercepting and triggering " - "a hard pause instead.") - self.loop.call_soon(self.request_pause, False) - print(PAUSE_MSG) - except asyncio.CancelledError as e: - # if we are handling this twice, raise and leave the plans - # alone - if self._exception is e: - raise e - # the case where FailedPause, RequestAbort or a coro - # raised error is not already stashed in _exception - if self._exception is None: - self._exception = e - pending_cancel_exception = e - except StopIteration: - pass - finally: - self.loop.stop() - self.state = 'idle' - # if the task was cancelled - if pending_cancel_exception is not None: - raise pending_cancel_exception - @asyncio.coroutine - def _sleep(self, msg): - yield from asyncio.sleep(msg.args[0]) - - @asyncio.coroutine - def _print(self, msg): - now = datetime.datetime.now - print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)) - - @asyncio.coroutine - def _sum(self, msg): - return sum(msg.args) - - @asyncio.coroutine - def _input(self, msg): - """ - Process a 'input' Msg. Expected Msg: - - Msg('input', None) - Msg('input', None, prompt='>') # customize prompt - """ - prompt = msg.kwargs.get('prompt', '') - async_input = AsyncInput(self.loop) - async_input = functools.partial(async_input, end='', flush=True) - return (yield from async_input(prompt)) - - @asyncio.coroutine - def _pause(self, msg): - """Request the run engine to pause - - Expected message object is: - - Msg('pause', defer=False, name=None, callback=None) - - See RunEngine.request_pause() docstring for explanation of the three - keyword arguments in the `Msg` signature - """ - self.request_pause(*msg.args, **msg.kwargs) - - def request_pause(self, defer=False): - """ - Command the Run Engine to pause. - - This function is called by 'pause' Messages. It can also be called - by other threads. It cannot be called on the main thread during a run, - but it is called by SIGINT (i.e., Ctrl+C). - - If there current run has no checkpoint (via the 'clear_checkpoint' - message), this will cause the run to abort. - - Parameters - ---------- - defer : bool, optional - If False, pause immediately before processing any new messages. - If True, pause at the next checkpoint. - False by default. - """ - if defer: - self._deferred_pause_requested = True - print("Deferred pause acknowledged. Continuing to checkpoint.") - return - - # We are pausing. Cancel any deferred pause previously requested. - self._deferred_pause_requested = False - self._interrupted = True - print("Pausing...") - self.state = 'paused' - if not self.resumable: - # cannot resume, so we cannot pause. Abort the scan - print("No checkpoint; cannot pause.") - print("Aborting: running cleanup and marking " - "exit_status as 'abort'...") - self._exception = FailedPause() - self._task.cancel() - for task in self._failed_status_tasks: - task.cancel() - return - # stop accepting new tasks in the event loop (existing tasks will - # still be processed) - self.loop.stop() - - def resume(self): - """Resume a paused plan from the last checkpoint. - - Returns - ------- - uids : list - list of Header uids (a.k.a RunStart uids) of run(s) - """ - # The state machine does not capture the whole picture. - if not self.state.is_paused: - raise TransitionError("The RunEngine is the {0} state. " - "You can only resume for the paused state." - "".format(self.state)) - - self._interrupted = False - new_plan = self._rewind() - self._plan_stack.append(new_plan) - self._response_stack.append(None) - - self._resume_event_loop() - return [] - - def _rewind(self): - '''Clean up in preparation for resuming from a pause or suspension. - - Returns - ------- - new_plan : generator - A new plan made from the messages in the message cache - - ''' - new_plan = ensure_generator(list(self._msg_cache)) - self._msg_cache = deque() - # This is needed to 'cancel' an open bundling (e.g. create) if - # the pause happens after a 'checkpoint', after a 'create', but before - # the paired 'save'. - return new_plan - - def _resume_event_loop(self): - # may be called by 'resume' or 'abort' - self.state = 'running' - self._last_sigint_time = None - self._num_sigints_processed = 0 - - if self._task.done(): - return - self.loop.run_forever() - if self._task.done() and not self._task.cancelled(): - exc = self._task.exception() - if exc is not None: - raise exc - - @asyncio.coroutine - def _checkpoint(self, msg): - """Instruct the RunEngine to create a checkpoint so that we can rewind - to this point if necessary - - Expected message object is: - - Msg('checkpoint') - """ - yield from self._reset_checkpoint_state_coro() - - if self._deferred_pause_requested: - # We are at a checkpoint; we are done deferring the pause. - # Give the _check_for_signals coroutine time to look for - # additional SIGINTs that would trigger an abort. - yield from asyncio.sleep(0.5, loop=self.loop) - self.request_pause(defer=False) - - def _reset_checkpoint_state(self): - if self._msg_cache is None: - return - - self._msg_cache = deque() - - _reset_checkpoint_state_coro = asyncio.coroutine(_reset_checkpoint_state) - - @asyncio.coroutine - def _clear_checkpoint(self, msg): - """Clear a set checkpoint - - Expected message object is: - - Msg('clear_checkpoint') - """ - # clear message cache - self._msg_cache = None - # clear stashed - self._teed_sequence_counters.clear() - - @asyncio.coroutine - def _rewindable(self, msg): - '''Set rewindable state of RunEngine - - Expected message object is: - - Msg('rewindable', None, bool or None) - ''' - - rw_flag, = msg.args - if rw_flag is not None: - self.rewindable = rw_flag - - return self.rewindable - - @asyncio.coroutine - def _null(self, msg): - """ - A no-op message, mainly for debugging and testing. - """ - pass - - - RE_v5 = RunEngine_v5() - RE_v5.msg_hook = print - - - def pausing_plan(): - yield Msg('null') - yield Msg('null') - yield Msg('pause') - yield Msg('null') - -Stop, Abort, Halt ------------------ - -Suspending ----------- - -Object/hardware clean up ------------------------- - -Document creation and emission ------------------------------- - -SIGINT interception -------------------- diff --git a/bluesky/_sources/run_engine.txt b/bluesky/_sources/run_engine.txt deleted file mode 100644 index 102fa3cd9a..0000000000 --- a/bluesky/_sources/run_engine.txt +++ /dev/null @@ -1,791 +0,0 @@ -The RunEngine run loop -====================== - -*Note: This is a technical document not optimized for user readability.* - -In this document, we start with a simplified version of the bluesky RunEngine. -We add more complexity step by step, with commentary. - -The heart of bluesky is the ``RunEngine._run`` co-routine which dispatches the -``Msg`` in the plan to functions that actually carry out the requested task. -The core operation is obscured by the layers of exception handling, state -management, and clean up the RunEngine is responsible for. (Some of this may -be refactored in the near future). This document is only going to discuss the -run loop, not Document generation or hardware clean up. - -Minimal RunEngine ------------------ - -A minimal (run-able) RunEngine is - -.. code:: python - - from time import sleep - import datetime - now = datetime.datetime.now - from bluesky import Msg - - function_map = {'print': - lambda msg: print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)), - 'sleep': - lambda msg: sleep(msg.args[0])} - - - def RE_v0(plan): - for msg in plan: - func = function_map[msg.command] - func(msg) - - welcome_plan = [Msg('print', 'hello'), Msg('sleep', None, 1), Msg('print', 'world!')] - - RE_v0(welcome_plan) - -which captures one of the key abstractions of bluesky: A plan is -just an iterable of messages. This abstraction means that the to plan an -experiment you only need to generate a stream of ``Msg`` objects and the -RunEngine will take care of actually executing the code. - -Adaptive Plans --------------- - -Simply having a stream of commands is not quite enough, you may want to -have the code generating the stream of messages be aware of the return -value of a previous ``Msg`` to decide what to do next. This sort of -thing is supported in python using -`generators `__ -which 'suspend' their execution at a ``yield`` statement. When you -iterate over a generator, it runs until the next ``yield`` -statement, suspends, and yields the value to the code which is iterating -over it. - -Switching to generators requires we change our minimal RE to - -.. code:: python - - from bluesky.utils import ensure_generator - - - - def RE_v1(plan): - plan = ensure_generator(plan) - last_result = None - - while True: - try: - msg = plan.send(last_result) - except StopIteration: - # generators indicate they are done by raising - # StopIteration - break - func = function_map[msg.command] - last_result = func(msg) - - -which still works with the ``welcome_plan`` - -.. code:: python - - RE_v1([Msg('print', 'hello'), Msg('sleep', None, 1), Msg('print', 'world!')]) - -but we can also do more sophisticated things like - -.. code:: python - - function_map['sum'] = lambda msg: sum(msg.args) - - def adding_plan(a, b): - yield Msg('print', '{} + {} = ??'.format(a, b)) - ret = yield Msg('sum', None, a, b) - yield Msg('print', '{} + {} = {}'.format(a, b, ret)) - yield Msg('print', 'thanks for adding') - -Which gives - -.. code:: python - - RE_v1(adding_plan(1, 2)) - RE_v1(adding_plan(5, 2)) - -This is obviously overkill for simple addition, but enables this like an -adaptive dscan that changes the step size based on the local slope. - -Exception Handling ------------------- - -In addition to ``generator.send`` (which inserts a value into the -generator) you can also use ``generator.throw`` which raises an -exception at the point where the generator is paused. If the generator -handles the exception (via a ``try...except`` block) then generator -runs until the next ``yield`` and ``throw`` returns the yielded -value. If the generator does not handle the exception (or raises a -different exception) then it is (re)raised by ``throw``. - -We want to be able to capture any exceptions raised by the ``RE`` -and pass those back to the plan. - -.. code:: python - - - def RE_v2(plan): - plan = ensure_generator(plan) - last_result = None - _exception = None - while True: - try: - if _exception is not None: - msg = plan.throw(_exception) - _exception = None - else: - msg = plan.send(last_result) - - except StopIteration: - break - try: - func = function_map[msg.command] - last_result = func(msg) - except Exception as e: - _exception = e - - -We can now write plans that handle exception from the RE, in this case -reporting that the addition failed due to a ``TypeError`` - -.. code:: python - - def safe_adding_plan(a, b): - yield Msg('print', '{} + {} = ??'.format(a, b)) - try: - ret = yield Msg('sum', None, a, b) - except TypeError: - yield Msg('print', 'can not add {} + {}!'.format(a, b)) - else: - yield Msg('print', '{} + {} = {}'.format(a, b, ret)) - finally: - yield Msg('print', 'thanks for adding') - -Compare the behavior of between ``adding_plan`` and ``addingplan`` in cases -where they succeed - -.. code:: python - - RE_v2(safe_adding_plan(1, 2)) - RE_v2(adding_plan(1, 2)) - -and fail - -.. code:: python - - RE_v2(safe_adding_plan('a', 2)) - RE_v2(adding_plan('a', 2)) - -Again, this is overkill for these simple cases, but this mechanism -allows us to write delta scans that always return the motors to their -original position, shut shutters, etc even if the plan fails or is -canceled. - -Turn into a callable class --------------------------- - -We are going to want to have access to the internal state of the -``_run`` loop very soon. An way to do this, while maintaining -the API we have above is to write a callable class instead of a -function. - -.. code:: python - - class RunEngine_v3: - def _sleep(self, msg): - sleep(msg.args[0]) - - def _print(self, msg): - print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)), - - def _sum(self, msg): - return sum(msg.args) - - def __init__(self): - self._command_registry = { - 'print': self._print, - 'sum': self._sum, - 'sleep': self._sleep} - - def __call__(self, plan): - self._run(plan) - - def _run(self, plan): - plan = ensure_generator(plan) - last_result = None - _exception = None - while True: - try: - if _exception is not None: - msg = plan.throw(_exception) - _exception = None - else: - msg = plan.send(last_result) - - except StopIteration: - break - try: - func = self._command_registry[msg.command] - last_result = func(msg) - except Exception as e: - _exception = e - - - RE_v3 = RunEngine_v3() - -In doing this we also pulled the function the commands dispatched to -into the class. While these methods are almost trivial, we will soon -have methods that alter the internal state of the ``RunEngine``. - -``asyncio`` integration ------------------------ - -So far all of these RE implementations have been synchronous functions, -that is they run straight through the plan. However, at a beamline we -need to be able to support asynchronous functionality and gracefully -interrupt the plan. - -To enable this we are using ``asyncio`` from the python standard library -(new in 3.4) to provide the outer event loop. At this point we are -integrating together two event loops: the RE loop which is processing -the plan and the ``asyncio`` event loop which is managing multiple -frames of execution. The event loop may switch between execution frames -when a coroutine is suspended by a ``yield from`` statement. Thus we -change the methods we dispatch to and the main ``_run`` method to -co-routines by adding the ``@asyncio.coroutine`` decorator and calling -the dispatched functions via ``yield from`` rather than with a direct -function call. - -We also added a ``msg_hook`` attribute to the ``RunEngine`` -which is a super handy debugging tool to see exactly what messages are -being processed by the RunEngine. It can be set to any callable which -takes a single ``Msg`` as input (ex ``print``) - -.. code:: python - - import asyncio - - - class RunEngine_v4: - def __init__(self, *, loop=None): - # map messages to coro - self._command_registry = { - 'print': self._print, - 'sum': self._sum, - 'sleep': self._sleep} - - # debugging hook - self.msg_hook = None - - - # bind RE to a specific loop - if loop is None: - loop = asyncio.get_event_loop() - self.loop = loop - - # The RunEngine keeps track of a *lot* of state. - # All flags and caches are defined here with a comment. Good luck. - self._task = None # asyncio.Task associated with call to self._run - - def __call__(self, plan): - self._task = self.loop.create_task(self._run(plan)) - self.loop.run_until_complete(self._task) - - if self._task.done() and not self._task.cancelled(): - exc = self._task.exception() - if exc is not None: - raise exc - - @asyncio.coroutine - def _run(self, plan): - plan = ensure_generator(plan) - last_result = None - _exception = None - while True: - try: - yield from asyncio.sleep(0.0001, loop=self.loop) - if _exception is not None: - msg = plan.throw(_exception) - _exception = None - else: - msg = plan.send(last_result) - - except StopIteration: - break - - if self.msg_hook: - self.msg_hook(msg) - - try: - func = self._command_registry[msg.command] - last_result = yield from func(msg) - except Exception as e: - _exception = e - - @asyncio.coroutine - def _sleep(self, msg): - yield from asyncio.sleep(msg.args[0]) - - @asyncio.coroutine - def _print(self, msg): - print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)), - - @asyncio.coroutine - def _sum(self, msg): - return sum(msg.args) - - - - RE_v4 = RunEngine_v4() - -Pausing, Resuming, and Rewinding --------------------------------- - -Adding the ability to pause/resume/rewind a scan adds a fair amount of -complexity as now the ``RunEngine`` must keep track of a stack of plans -rather than a single plan, cache ``Msg`` as they go by and expose enough -API to control the behavior. - -.. code:: python - - from collections import deque - import asyncio - - import datetime - import functools - from bluesky.utils import (AsyncInput, FailedPause, InvalidCommand, Msg, - ensure_generator) - from bluesky.run_engine import RunEngineStateMachine, PropertyMachine - from super_state_machine.errors import TransitionError - - - class RunEngine_v5: - state = PropertyMachine(RunEngineStateMachine) - _UNCACHEABLE_COMMANDS = ['pause', ] - - def __init__(self, *, loop=None): - # map messages to coro - self._command_registry = { - 'print': self._print, - 'sum': self._sum, - # coros on real RE - 'sleep': self._sleep, - 'checkpoint': self._checkpoint, - 'clear_checkpoint': self._clear_checkpoint, - 'rewindable': self._rewindable, - 'pause': self._pause, - 'input': self._input, - 'null': self._null, } - - # debugging hook - self.msg_hook = None - - # bind RE to a specific loop - if loop is None: - loop = asyncio.get_event_loop() - self.loop = loop - - # The RunEngine keeps track of a *lot* of state. - # All flags and caches are defined here with a comment. Good luck. - self._task = None # asyncio.Task associated with call to self._run - - self._deferred_pause_requested = False # pause at next 'checkpoint' - self._msg_cache = deque() # history of processed msgs for rewinding - self._rewindable_flag = True # if the RE is allowed to replay msgs - self._plan = None # the scan plan instance from __call__ - self._plan_stack = deque() # stack of generators to work off of - self._response_stack = deque([None]) # resps to send into the plans - self._interrupted = False # True if paused, aborted, or failed - - def __call__(self, plan): - # First thing's first: if we are in the wrong state, raise. - if not self.state.is_idle: - raise RuntimeError("The RunEngine is in a %s state" % self.state) - - self._clear_call_cache() - - self._plan = plan - gen = ensure_generator(plan) - - self._plan_stack.append(gen) - self._response_stack.append(None) - - self._task = self.loop.create_task(self._run()) - self.loop.run_forever() - - if self._task.done() and not self._task.cancelled(): - exc = self._task.exception() - if exc is not None: - raise exc - - def _clear_call_cache(self): - self._deferred_pause_requested = False - self._plan_stack = deque() - self._msg_cache = deque() - self._response_stack = deque([None]) - self._exception = None - self._task = None - self._plan = None - self._interrupted = False - - @property - def rewindable(self): - return self._rewindable_flag - - @rewindable.setter - def rewindable(self, v): - cur_state = self._rewindable_flag - self._rewindable_flag = bool(v) - if self.resumable and self._rewindable_flag != cur_state: - self._reset_checkpoint_state() - - @property - def resumable(self): - "i.e., can the plan in progress by rewound" - return self._msg_cache is not None - - @asyncio.coroutine - def _run(self): - pending_cancel_exception = None - try: - self.state = 'running' - while True: - try: - yield from asyncio.sleep(0.0001, loop=self.loop) - # The case where we have a stashed exception - if self._exception is not None: - # throw the exception at the current plan - try: - msg = self._plan_stack[-1].throw( - self._exception) - except Exception as e: - # The current plan did not handle it, - # maybe the next plan (if any) would like - # to try - self._plan_stack.pop() - if len(self._plan_stack): - self._exception = e - continue - # no plans left and still an unhandled exception - # re-raise to exit the infinite loop - else: - raise - # clear the stashed exception, the top plan - # handled it. - else: - self._exception = None - # The normal case of clean operation - else: - resp = self._response_stack.pop() - try: - msg = self._plan_stack[-1].send(resp) - # We have exhausted the top generator - except StopIteration: - # pop the dead generator go back to the top - self._plan_stack.pop() - if len(self._plan_stack): - continue - # or reraise to get out of the infinite loop - else: - raise - # Any other exception that comes out of the plan - except Exception as e: - # pop the dead plan, stash the exception and - # go to the top of the loop - self._plan_stack.pop() - if len(self._plan_stack): - self._exception = e - continue - # or reraise to get out of the infinite loop - else: - raise - - if self.msg_hook: - self.msg_hook(msg) - - # if this message can be cached for rewinding, cache it - if (self._msg_cache is not None and - self._rewindable_flag and - msg.command not in self._UNCACHEABLE_COMMANDS): - # We have a checkpoint. - self._msg_cache.append(msg) - - # try to look up the coroutine to execute the command - try: - coro = self._command_registry[msg.command] - # replace KeyError with a local sub-class and go - # to top of the loop - except KeyError: - # TODO make this smarter - self._exception = InvalidCommand(msg.command) - continue - - # try to finally run the command the user asked for - try: - # this is one of two places that 'async' - # exceptions (coming in via throw) can be - # raised - response = yield from coro(msg) - # special case `CancelledError` and let the outer - # exception block deal with it. - except asyncio.CancelledError: - raise - # any other exception, stash it and go to the top of loop - except Exception as e: - self._exception = e - continue - # normal use, if it runs cleanly, stash the response and - # go to the top of the loop - else: - self._response_stack.append(response) - continue - - except KeyboardInterrupt: - # This only happens if some external code captures SIGINT - # -- overriding the RunEngine -- and then raises instead - # of (properly) calling the RunEngine's handler. - # See https://github.com/NSLS-II/bluesky/pull/242 - print("An unknown external library has improperly raised " - "KeyboardInterrupt. Intercepting and triggering " - "a hard pause instead.") - self.loop.call_soon(self.request_pause, False) - print(PAUSE_MSG) - except asyncio.CancelledError as e: - # if we are handling this twice, raise and leave the plans - # alone - if self._exception is e: - raise e - # the case where FailedPause, RequestAbort or a coro - # raised error is not already stashed in _exception - if self._exception is None: - self._exception = e - pending_cancel_exception = e - except StopIteration: - pass - finally: - self.loop.stop() - self.state = 'idle' - # if the task was cancelled - if pending_cancel_exception is not None: - raise pending_cancel_exception - @asyncio.coroutine - def _sleep(self, msg): - yield from asyncio.sleep(msg.args[0]) - - @asyncio.coroutine - def _print(self, msg): - now = datetime.datetime.now - print('-- {!s:10.10s} : {: <25.25s} --'.format(now().time(), msg.obj)) - - @asyncio.coroutine - def _sum(self, msg): - return sum(msg.args) - - @asyncio.coroutine - def _input(self, msg): - """ - Process a 'input' Msg. Expected Msg: - - Msg('input', None) - Msg('input', None, prompt='>') # customize prompt - """ - prompt = msg.kwargs.get('prompt', '') - async_input = AsyncInput(self.loop) - async_input = functools.partial(async_input, end='', flush=True) - return (yield from async_input(prompt)) - - @asyncio.coroutine - def _pause(self, msg): - """Request the run engine to pause - - Expected message object is: - - Msg('pause', defer=False, name=None, callback=None) - - See RunEngine.request_pause() docstring for explanation of the three - keyword arguments in the `Msg` signature - """ - self.request_pause(*msg.args, **msg.kwargs) - - def request_pause(self, defer=False): - """ - Command the Run Engine to pause. - - This function is called by 'pause' Messages. It can also be called - by other threads. It cannot be called on the main thread during a run, - but it is called by SIGINT (i.e., Ctrl+C). - - If there current run has no checkpoint (via the 'clear_checkpoint' - message), this will cause the run to abort. - - Parameters - ---------- - defer : bool, optional - If False, pause immediately before processing any new messages. - If True, pause at the next checkpoint. - False by default. - """ - if defer: - self._deferred_pause_requested = True - print("Deferred pause acknowledged. Continuing to checkpoint.") - return - - # We are pausing. Cancel any deferred pause previously requested. - self._deferred_pause_requested = False - self._interrupted = True - print("Pausing...") - self.state = 'paused' - if not self.resumable: - # cannot resume, so we cannot pause. Abort the scan - print("No checkpoint; cannot pause.") - print("Aborting: running cleanup and marking " - "exit_status as 'abort'...") - self._exception = FailedPause() - self._task.cancel() - for task in self._failed_status_tasks: - task.cancel() - return - # stop accepting new tasks in the event loop (existing tasks will - # still be processed) - self.loop.stop() - - def resume(self): - """Resume a paused plan from the last checkpoint. - - Returns - ------- - uids : list - list of Header uids (a.k.a RunStart uids) of run(s) - """ - # The state machine does not capture the whole picture. - if not self.state.is_paused: - raise TransitionError("The RunEngine is the {0} state. " - "You can only resume for the paused state." - "".format(self.state)) - - self._interrupted = False - new_plan = self._rewind() - self._plan_stack.append(new_plan) - self._response_stack.append(None) - - self._resume_event_loop() - return [] - - def _rewind(self): - '''Clean up in preparation for resuming from a pause or suspension. - - Returns - ------- - new_plan : generator - A new plan made from the messages in the message cache - - ''' - new_plan = ensure_generator(list(self._msg_cache)) - self._msg_cache = deque() - # This is needed to 'cancel' an open bundling (e.g. create) if - # the pause happens after a 'checkpoint', after a 'create', but before - # the paired 'save'. - return new_plan - - def _resume_event_loop(self): - # may be called by 'resume' or 'abort' - self.state = 'running' - self._last_sigint_time = None - self._num_sigints_processed = 0 - - if self._task.done(): - return - self.loop.run_forever() - if self._task.done() and not self._task.cancelled(): - exc = self._task.exception() - if exc is not None: - raise exc - - @asyncio.coroutine - def _checkpoint(self, msg): - """Instruct the RunEngine to create a checkpoint so that we can rewind - to this point if necessary - - Expected message object is: - - Msg('checkpoint') - """ - yield from self._reset_checkpoint_state_coro() - - if self._deferred_pause_requested: - # We are at a checkpoint; we are done deferring the pause. - # Give the _check_for_signals coroutine time to look for - # additional SIGINTs that would trigger an abort. - yield from asyncio.sleep(0.5, loop=self.loop) - self.request_pause(defer=False) - - def _reset_checkpoint_state(self): - if self._msg_cache is None: - return - - self._msg_cache = deque() - - _reset_checkpoint_state_coro = asyncio.coroutine(_reset_checkpoint_state) - - @asyncio.coroutine - def _clear_checkpoint(self, msg): - """Clear a set checkpoint - - Expected message object is: - - Msg('clear_checkpoint') - """ - # clear message cache - self._msg_cache = None - # clear stashed - self._teed_sequence_counters.clear() - - @asyncio.coroutine - def _rewindable(self, msg): - '''Set rewindable state of RunEngine - - Expected message object is: - - Msg('rewindable', None, bool or None) - ''' - - rw_flag, = msg.args - if rw_flag is not None: - self.rewindable = rw_flag - - return self.rewindable - - @asyncio.coroutine - def _null(self, msg): - """ - A no-op message, mainly for debugging and testing. - """ - pass - - - RE_v5 = RunEngine_v5() - RE_v5.msg_hook = print - - - def pausing_plan(): - yield Msg('null') - yield Msg('null') - yield Msg('pause') - yield Msg('null') - -Stop, Abort, Halt ------------------ - -Suspending ----------- - -Object/hardware clean up ------------------------- - -Document creation and emission ------------------------------- - -SIGINT interception -------------------- diff --git a/bluesky/_sources/run_engine_api.rst.txt b/bluesky/_sources/run_engine_api.rst.txt deleted file mode 100644 index 1ea48e4b56..0000000000 --- a/bluesky/_sources/run_engine_api.rst.txt +++ /dev/null @@ -1,200 +0,0 @@ -.. currentmodule:: bluesky.run_engine - -RunEngine API Documentation -=========================== - -The ``RunEngine`` ------------------ - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine - -The main user entry point tho the RunEngine is ``RE(my_plan(...))`` - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine.__call__ - -The RunEngine maintains a callback registry of functions that receive any -:doc:`documents` generated by plan execution. These methods add and remove -functions from that registry. - - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine.subscribe - RunEngine.unsubscribe - -When the RunEngine is in a paused state, it can be resumed or stopped in -:ref:`various ways ` using these methods: - - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine.resume - RunEngine.abort - RunEngine.stop - RunEngine.halt - -The RunEngine can suspend and resume plan execution in response to external -changes. See :ref:`suspenders`. - - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine.install_suspender - RunEngine.remove_suspender - RunEngine.clear_suspenders - -These methods are used internally to pause or suspend the RunEngine. -Typically the user accomplishes this with Ctrl+C or by installing -suspenders, respectively. For special applicaitons, they can be called -directly. - - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine.request_pause - RunEngine.request_suspend - -These methods may be used to register custom commands to supplement or -replace the built-in commands recognized by the RunEngine. - - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine.register_command - RunEngine.unregister_command - -These methods may be used to list the commands available, or print -a summary as to what they do. - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngine.print_command_registry - RunEngine.commands - -A RunEngine encapsulates a :class:`Dispatcher` for emitting any -:doc:`documents` generated by plan execution. The methods -:meth:`RunEngine.subscribe` and :meth:`RunEngine.unsubscribe`, documented -above, are aliases to the corresponding methods on the RunEngine's Dispatcher. - - -The ``Dispatcher`` ------------------- - - -.. autosummary:: - :nosignatures: - :toctree: generated - - Dispatcher - Dispatcher.subscribe - Dispatcher.unsubscribe - Dispatcher.unsubscribe_all - Dispatcher.process - - -The ``RunBundler`` ------------------- - - -The RunEngine also creates `RunBundler`\s instances to encapsulate the -logic and book keeping for generating events (and allow multiple runs -to be open at once). In general you should not be directly working with -a `RunBundler`. - -.. currentmodule:: bluesky.bundlers - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler - -The co-routines for opening and closing a run. - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler.open_run - RunBundler.close_run - -The co-routines for opening / filling / closing / dropping an Event - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler.create - RunBundler.read - RunBundler.drop - RunBundler.save - -The co-routines for managing flyers - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler.kickoff - RunBundler.complete - RunBundler.collect - RunBundler.backstop_collect - -The co-routines for changing a device configuration - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler.configure - -The co-routines for managing monitors - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler.monitor - RunBundler.suspend_monitors - RunBundler.restore_monitors - RunBundler.clear_monitors - RunBundler.unmonitor - -The co-routines for checkpoint management - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler.clear_checkpoint - RunBundler.reset_checkpoint_state - RunBundler.reset_checkpoint_state_coro - RunBundler.rewind - -The co-routines to record interruptions - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunBundler.record_interruption diff --git a/bluesky/_sources/simple_api.txt b/bluesky/_sources/simple_api.txt deleted file mode 100644 index 30120b9490..0000000000 --- a/bluesky/_sources/simple_api.txt +++ /dev/null @@ -1,230 +0,0 @@ -(Optional) SPEC-like Interface -============================== - -.. warning:: - - The SPEC-like interface was changed in bluesky v0.5.0, and this - documentation has not yet been updated. It will be updated before the - start of the Summer 2016 cycle. Until then, consult the DAMA group with - any questions. - -Conceptual Differences Between Bluesky and SPEC ------------------------------------------------ - -Some scientists are familiar with `SPEC `_, -a domain-specific language for hardware control. It is possible to imitate the -SPEC workflow on top of bluesky. Of course, we still adhere to the Python -syntax so that we can employ the full power of the general-purpose Python -language. - -It is useful to understand a key conceptual difference between bluesky and -SPEC. SPEC treats the *specification* of an experiment ("move a motor from 1 -to 5 in 5 strides") and its *execution* in one step. For example, in SPEC, -typing - -.. code-block:: bash - - ascan th, 1, 5, 5 - -both specifies and executes the scan. Fundamentally, bluesky separates these -steps: first we generate a "plan" (a set of granular instructions) - -.. code-block:: python - - plan = AbsScanPlan(detectors, th, 1, 5, 4) - -and then we pass the plan to a RunEninge for execution. - -.. code-block:: python - - RE(plan) - -To imitate the SPEC workflow, these two steps are lumped together. - -.. code-block:: python - - ascan(th, 1, 5, 5) # this is bluesky's imitation of SPEC - -For simple tasks, the condensed syntax is clearly convenient; for others, -maintaining that logical separation can be empowering. (See the section on -:doc:`plans` for why.) - -Addiontally, SPEC maintains a global list of detectors that apply to all scans. -Bluesky specifies detectors on a per-plan basis: for example, a "count" might -involve different detectors than an "ascan". But, to imitate SPEC, bluesky -provides a global "stash" of settings, ``gs``, including a customizable list of -"standard" detectors, as illustrated below. - -.. ipython:: python - :suppress: - - from bluesky.examples import det1, det2, det3, det - from bluesky.global_state import gs - from bluesky.spec_api import * # the simple scan instances - from bluesky.tests.utils import setup_test_run_engine - gs.DETS = [det] - gs.RE = setup_test_run_engine() - - -Specify Detectors ------------------ - -.. note:: - - If you are using a IPython profile, a list of detectors might be - automatically specified at startup. In that case, you may not need to do - anything unless you need to inspect or customize that list. - -The setting ``gs.DETS`` is a list of a detector objects. It controls -which detectors are triggered and read by all the simple scans. -(Incidentally, ``gs`` stands for "global state" or "global settings." Why -can't it just be plain ``DETS``? Global variables are best avoided in Python, -and the ``gs.`` part provides useful input validation.) - -.. ipython:: python - - gs.DETS = [det1, det2] - -Like any Python list, you can append and remove elements. - -.. ipython:: python - - gs.DETS.append(det3) - gs.DETS.remove(det1) - gs.DETS - -There are other settings which control the output of the scans -- -``gs.TABLE_COLS`` and ``gs.PLOT_Y`` for example. Explore the contents of -``gs`` by typing ``gs.``. - -Peak Stats ----------- - - - -Live Plotting -------------- - -Count ------ - -A ``ct`` ("count") scan reads all the detectors in the list ``DETS`` for -a given acquisition time. If no time is specified, 1 second is the default. - -.. code-block:: python - - ct(time=1) - -Motor Scans ------------ - -Like ``ct``, the motor scans read from all the detectors in the list -``DETS``. - -Absolute Scans -^^^^^^^^^^^^^^ - -An ``ascan`` ("absolute scan") scans one motor in equal-sized steps. - -.. code-block:: python - - ascan(motor, start, finish, intervals, time) - -Note that ``intervals`` counts the number of *steps* which is one less -than the number of *data points*. This follows the convention in SPEC. -Outside of the simple API, we revert to the Python convention of counting -data points, not steps. - -An ``a2scan`` scans two motors together along different trajectories, -again in equal-sized steps. (We think of this as the "inner product" of two -trajectories.) - -.. code-block:: python - - a2scan(motor1, start1, finish1, motor2, start2, finish2, intervals, time) - -.. code-block:: python - - a3scan(motor1, start1, finish1, motor2, start2, finish2, motor3, - start3, finish3, intervals, time) - -We provide ``a2scan`` and ``a3scan`` for convenience, but in fact both of them -support any number of motors. This is valid: - -.. code-block:: python - - a2scan(motor1, start1, finish1, motor2, start2, finish2, motor3, start3, - finish3, motor4, start4, finish4, intervals, time) - -Delta Scans -^^^^^^^^^^^ - -A ``dscan`` ("delta scan") scans one motor in equal-size steps, specified -relative to the motor's current position. - -.. code-block:: python - - dscan(motor, start, finish, intervals, time) - -``lup`` is an alias for ``dscan``. And as with ``ascan`` above, there is a -``d2scan`` and a ``d3scan``, each of which accept an unlimited number of -motors. - -Mesh Scan -^^^^^^^^^ - -A ``mesh`` scan scans any number of motors in a mesh. (We think of this as the -"other product" of the trajectories.) - -.. code-block:: python - - mesh(motor1, start1, finish1, intervals1, motor2, start2, finish2, - intervals2, time) - -As with ``a2scan`` and ``a3scan``, ``mesh`` accepts any number of motors. -Notice that the number of intervals is specified sepraately for each motor. - -Scans Tied to Particular Motors / Controllers ---------------------------------------------- - -Theta Two Theta -^^^^^^^^^^^^^^^ - -This scan requires the settings ``gs.TH_MOTOR`` ("theta motor") and -``gs.TTH_MOTOR`` ("two theta motor"). - -A ``th2th`` ("theta two theta") scans steps the two theta motor through a -given range while stepping the theta motor through half that range. - -.. code-block:: python - - th2th(start, finish, intervals, time) - -Temperature Scans -^^^^^^^^^^^^^^^^^ - -Temperature scans require the setting ``gs.TEMP_CONTROLLER``. - -A ``tscan`` steps the temperature controller through equally-spaced temperature -set points. An optional ``sleep`` argument specifies a thermalization time. As -in SPEC, it is zero by default. - -.. code-block:: python - - tscan(start, finish, intervals, time, sleep=0) - -There is also ``dtscan``, a relative temperature scan. - -Tweak ------ - -Tweak is an interactive scan that reads a field from one detector, displays -the result, and prompts the user to specify where to step the motor next. -It requires the setting ``gs.MASTER_DET`` (which detector to use, -such as ``sclr``) and ``MASTER_DET_FIELD`` (the name of the field in that -detector to read out, such as ``'sclr_chan4'``). Note that the former is a -readable object and the latter is a string of text. - -.. code-block:: python - - tw(motor, step) diff --git a/bluesky/_sources/simulation.rst.txt b/bluesky/_sources/simulation.rst.txt deleted file mode 100644 index 0709a47cf6..0000000000 --- a/bluesky/_sources/simulation.rst.txt +++ /dev/null @@ -1,93 +0,0 @@ -.. currentmodule:: bluesky.simulators - -Simulation and Error Checking -============================= - -Bluesky provides three different approaches for simulating a plan without -actually executing it: - -1. Introspect a plan by passing it to a "simulator" instead of a RunEngine. -2. Execute a plan with the real RunEngine, but use simulated hardware objects. -3. Redefine the RunEngine commands to change their meanings. - -Approaches (1) and (2) are the most straightforward and most common. - -Introspection -------------- - -Recall that plans yield messages that *describe* what should be done; they -do not communicate with hardware directly. Therefore it's easy to use (or -write) a simple function that iterates through the plan and summarizes or -analyzes its actions. - -.. autosummary:: - :toctree: generated - :nosignatures: - - summarize_plan - plot_raster_path - check_limits - -Summarize -^^^^^^^^^ - -The simulator :func:`summarize_plan` print a summary of what a plan would do if -executed by the RunEngine. - -.. ipython:: python - - from bluesky.simulators import summarize_plan - from ophyd.sim import det, motor - from bluesky.plans import scan - summarize_plan(scan([det], motor, 1, 3 ,3)) - -To see the unabridged contents of a plan, simply use the builtin Python -function :func:`list`. Note that it is not possible to summarize plans that -have adaptive logic because their contents are determined dynamically during -plan executation. - -.. ipython:: python - - list(scan([det], motor, 1, 3 ,3)) - -Check Limits -^^^^^^^^^^^^ - -.. ipython:: python - :suppress: - - motor.limits = (-1000, 1000) - -Suppose that this motor is configured with limits on its range of motion at +/- -1000. The :func:`check_limits` simulator can verify whether or not a plan will -violate these limits, saving you from discovering this part way through a long -experiment. - -.. ipython:: python - :okexcept: - - from bluesky.simulators import check_limits - - check_limits(scan([det], motor, 1, 3 ,3)) # no problem here - check_limits(scan([det], motor, 1, -3000, 3000)) # should raise an error - -Simulated Hardware ------------------- - -.. warning:: - - This feature has recently been changed, and it has yet to be documented. - -Customizing RunEngine Methods ------------------------------ - -The RunEngine allows you to customize the meaning of commands (like 'set' and -'read'). One could use this feature to create a dummy RunEngine that, instead -of actually reading and writing to hardware, merely reports what it *would* -have done. - -.. automethod:: bluesky.run_engine.RunEngine.register_command - :noindex: - -.. automethod:: bluesky.run_engine.RunEngine.unregister_command - :noindex: diff --git a/bluesky/_sources/state-machine.rst.txt b/bluesky/_sources/state-machine.rst.txt deleted file mode 100644 index 120ad2735d..0000000000 --- a/bluesky/_sources/state-machine.rst.txt +++ /dev/null @@ -1,483 +0,0 @@ -Interruptions -************* - -The RunEngine can be safely interrupted and resumed. All plans get this -feature "for free." - -.. _pausing_interactively: - -Pausing Interactively -===================== - -.. note:: - - Looking for a quick refresher on pausing, resuming, or aborting - interactively? Skip to the :ref:`interactive_pause_summary`. - -While the RunEngine is executing a plan, it captures SIGINT (Ctrl+C). - -Pause Now: Ctrl+C twice ------------------------ - -.. code-block:: python - - In [14]: RE(scan([det], motor, 1, 10, 10)) - Transient Scan ID: 2 Time: 2018/02/12 12:43:12 - Persistent Unique Scan ID: '33a16823-e214-4952-abdd-032a78b8478f' - New stream: 'primary' - +-----------+------------+------------+------------+ - | seq_num | time | motor | det | - +-----------+------------+------------+------------+ - | 1 | 12:43:13.3 | 1.000 | 0.607 | - | 2 | 12:43:14.3 | 2.000 | 0.135 | - | 3 | 12:43:15.3 | 3.000 | 0.011 | - ^C - A 'deferred pause' has been requested. The RunEngine will pause at the next checkpoint. To pause immediately, hit Ctrl+C again in the next 10 seconds. - Deferred pause acknowledged. Continuing to checkpoint. - ^C - Pausing... - --------------------------------------------------------------------------- - RunEngineInterrupted Traceback (most recent call last) - in () - ----> 1 RE(scan([det], motor, 1, 10, 10)) - - ~/Documents/Repos/bluesky/bluesky/run_engine.py in __call__(self, *args, **metadata_kw) - 670 - 671 if self._interrupted: - --> 672 raise RunEngineInterrupted(self.pause_msg) from None - 673 - 674 return tuple(self._run_start_uids) - - RunEngineInterrupted: - Your RunEngine is entering a paused state. These are your options for changing - the state of the RunEngine: - - RE.resume() Resume the plan. - RE.abort() Perform cleanup, then kill plan. Mark exit_stats='aborted'. - RE.stop() Perform cleanup, then kill plan. Mark exit_status='success'. - RE.halt() Emergency Stop: Do not perform cleanup --- just stop. - -Before returning the prompt to the user, the RunEngine ensures that all motors -that it has touched are stopped. It also performs any device-specific cleanup -defined in the device's (optional) ``pause()`` method. - -If execution is later resumed, the RunEngine will "rewind" through the plan to -the most recent :ref:`checkpoint `, the last safe place to restart. - -Pause Soon: Ctrl+C once ------------------------ - -Pause at the next :ref:`checkpoint `: typically, the next step in -a step scan. We call this "deferred pause." It avoids having to repeat any work -when the plan is resumed. - -Notice that this time when Ctrl+C (^C) is hit, the current step (4) is allowed -to complete before execution is paused. - -.. code-block:: python - - In [12]: RE(scan([det], motor, 1, 10, 10)) - Transient Scan ID: 1 Time: 2018/02/12 12:40:36 - Persistent Unique Scan ID: 'c5db9bb4-fb7f-49f4-948b-72fb716d1f67' - New stream: 'primary' - +-----------+------------+------------+------------+ - | seq_num | time | motor | det | - +-----------+------------+------------+------------+ - | 1 | 12:40:37.6 | 1.000 | 0.607 | - | 2 | 12:40:38.7 | 2.000 | 0.135 | - | 3 | 12:40:39.7 | 3.000 | 0.011 | - ^CA 'deferred pause' has been requested. The RunEngine will pause at the next checkpoint. To pause immediately, hit Ctrl+C again in the next 10 seconds. - Deferred pause acknowledged. Continuing to checkpoint. - | 4 | 12:40:40.7 | 4.000 | 0.000 | - Pausing... - --------------------------------------------------------------------------- - RunEngineInterrupted Traceback (most recent call last) - in () - ----> 1 RE(scan([det], motor, 1, 10, 10)) - - ~/Documents/Repos/bluesky/bluesky/run_engine.py in __call__(self, *args, **metadata_kw) - 670 - 671 if self._interrupted: - --> 672 raise RunEngineInterrupted(self.pause_msg) from None - 673 - 674 return tuple(self._run_start_uids) - - RunEngineInterrupted: - Your RunEngine is entering a paused state. These are your options for changing - the state of the RunEngine: - - RE.resume() Resume the plan. - RE.abort() Perform cleanup, then kill plan. Mark exit_stats='aborted'. - RE.stop() Perform cleanup, then kill plan. Mark exit_status='success'. - RE.halt() Emergency Stop: Do not perform cleanup --- just stop. - -What to do after pausing ------------------------- - -After being paused, the RunEngine holds on to information that it might need in -order to resume later. It "knows" that it is in a paused state, and you can -check that at any time: - -.. code-block:: python - - In [2]: RE.state - Out[2]: 'paused' - - -During the pause, we can do anything: check readings, move motors, etc. It will -not allow you to execute a new plan until the current one is either resumed or -terminated. Your options are: - -Resume -^^^^^^ - -.. code-block:: python - - In [3]: RE.resume() - | 4 | 07:21:29.5 | -5.714 | 0.000 | - | 5 | 07:21:29.5 | -4.286 | 0.000 | - | 6 | 07:21:29.6 | -2.857 | 0.017 | - | 7 | 07:21:29.7 | -1.429 | 0.360 | - (etc.) - -Depending on the plan, it may "rewind" to safely continue on and ensure all -data is collected correctly. - -Abort -^^^^^ - -Allow the plan to perform any final cleanup. For example, some plans move -motors back to their starting positions. Mark the data as having been aborted, -so that this fact can be noted (if desired) in later analysis. All of the data -collected up this point will be saved regardless. - -From a paused state: - -.. code-block:: python - - In [3]: RE.abort() - Aborting... - Out[3]: ['8ef9388c-75d3-498c-a800-3b0bd24b88ed'] - -Stop -^^^^ - -``RE.stop()`` is functionally identical to ``RE.abort()``. The only -difference is that aborted runs are marked with ``exit_status: 'abort'`` -instead of ``exit_status: 'success'``. This may be a useful distinction -during analysis. - -Halt -^^^^ - -Aborting or stopping allows the plan to perform cleanup. We already mentioned -the example of a plan moving motors back to their starting positions at the -end. - -In some situations, you may wish to prevent the plan from doing *anything* ---- you want to halt immediately, skipping cleanup. For this, use -``RE.halt()``. - -.. _interactive_pause_summary: - -Summary -------- - -Interactively Interrupt Execution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -======================= =========== -Command Outcome -======================= =========== -Ctrl+C Pause soon. -Ctrl+C twice Pause now. -======================= =========== - -From a paused state -^^^^^^^^^^^^^^^^^^^ - -============== =========== -Command Outcome -============== =========== -RE.resume() Safely resume plan. -RE.abort() Perform cleanup. Mark as aborted. -RE.stop() Perform cleanup. Mark as success. -RE.halt() Do not perform cleanup --- just stop. -RE.state Check if 'paused' or 'idle'. -============== =========== - -.. _suspenders: - -Automated Suspension -==================== - -It can also be useful to interrupt execution automatically in response to some -condition (e.g., shutter closed, beam dumped, temperature exceeded some limit). -We use the word *suspension* to mean an unplanned pause initialized by some -agent running the background. The agent (a "suspender") monitors some condition -and, if it detects a problem, it suspends execution. When it detects that -conditions have returned to normal, it gives the RunEngine permission to resume -after some interval. This can operate unattended. - -.. ipython:: - :verbatim: - - In [1]: RE(scan([det], motor, -10, 10, 15), LiveTable([motor, det])) - +------------+-------------------+----------------+----------------+ - | seq_num | time | motor | det | - +------------+-------------------+----------------+----------------+ - | 1 | 16:46:08.953815 | 0.03 | 290.00 | - Suspending....To get prompt hit Ctrl-C to pause the scan - | 2 | 16:46:20.868445 | 0.09 | 279.00 | - | 3 | 16:46:29.077690 | 0.16 | 284.00 | - | 4 | 16:46:33.540643 | 0.23 | 278.00 | - +------------+-------------------+----------------+----------------+ - -A *suspended* plan does not return the prompt to the user. Like a paused plan, -it stops executing new instructions and rewinds to the most recent checkpoint. -But unlike a paused plan, it resumes execution automatically when conditions -return to normal. - -To take manual control of a suspended plan, pause it by hitting Ctrl+C twice. -You will be given the prompt. When conditions are good again, you may manually -resume using ``RE.resume()``. - -.. _installing_suspenders: - -Installing Suspenders ---------------------- - -Bluesky includes several "suspenders" that work with ophyd Signals to monitor -conditions and suspend execution. It's also possible to write suspenders -from scratch to monitor anything at all. - -We'll start with an example. - -Example: Suspend a plan if the beam current dips low -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This defines a suspender and installs it on the RunEngine. With this, plans -will be automatically suspended when the ``beam_current`` signal goes below 2 -and resumed once it exceeds 3. - -.. code-block:: python - - from ophyd import EpicsSignal - from bluesky.suspenders import SuspendFloor - - beam_current = EpicsSignal('...PV string...') - sus = SuspendFloor(beam_current, 2, resume_thresh=3) - RE.install_suspender(sus) - -In the following example, the beam current dipped below 2 in the middle of -taking the second data point. It later recovered. - -.. ipython:: - :verbatim: - - In [6]: RE(my_scan) - +------------+-------------------+----------------+----------------+ - | seq_num | time | theta | sclr_chan4 | - +------------+-------------------+----------------+----------------+ - | 1 | 16:46:08.953815 | 0.03 | 290.00 | - Suspending....To get prompt hit Ctrl-C to pause the scan - | 2 | 16:46:20.868445 | 0.09 | 279.00 | - | 3 | 16:46:29.077690 | 0.16 | 284.00 | - | 4 | 16:46:33.540643 | 0.23 | 278.00 | - +------------+-------------------+----------------+----------------+ - -Notice that the plan was suspended and then resumed. When it resumed, it went -back to the last checkpoint and re-took the second data point cleanly. - -See the API documentation (follow the links in the table below) for other -suspender types and options, including a waiting period and cleanup -procedures to run pre-suspend and pre-resume. - -Built-in Suspenders -------------------- - -.. autosummary:: - :toctree: generated - :nosignatures: - - bluesky.suspenders.SuspendBoolHigh - bluesky.suspenders.SuspendBoolLow - bluesky.suspenders.SuspendFloor - bluesky.suspenders.SuspendCeil - bluesky.suspenders.SuspendWhenOutsideBand - bluesky.suspenders.SuspendWhenChanged - -.. _checkpoints: - -Checkpoints -=========== - -Plans are specified as a sequence of :ref:`messages `, granular -instructions like 'read' and 'set'. The messages can optionally include one -or more 'checkpoint' messages, indicating a place where it is safe to resume -after an interruption. For example, checkpoints are placed before each step of a -:func:`bluesky.plans.scan`. - -Some experiments are not resumable: for example, the sample may be melting or -aging. Incorporating :func:`bluesky.plan_stubs.clear_checkpoint` in a plan -makes it un-resuming. If a pause or suspension are requested, the plan will -abort instead. - -.. note:: - - Some details about checkpoints and when they are allowed: - - It is not legal to create a checkpoint in the middle of a data point - (between 'create' and 'save'). Checkpoints are implicitly created after - actions that it is not safe to replay: staging a device, adding a - monitor, or adding a subscription. - -.. _planned_pauses: - -Planned Pauses -============== - -Pausing is typically done :ref:`interactively ` (Ctrl+C) -but it can also be incorporated into a plan. The plan can pause the RunEngine, -requiring the user to type ``RE.resume()`` to continue or ``RE.stop()`` -(or similar) to clean up and stop. - -.. code-block:: python - - import bluesky.plan_stubs as bps - - def pausing_plan(): - while True: - yield from some_plan(...) - print("Type RE.resume() to go again or RE.stop() to stop.") - yield from bps.checkpoint() # marking where to resume from - yield from bps.pause() - -Associated RunEngine Interface -============================== - -State ------ - -The RunEngine has a state machine defining its phases of operation and the -allowed transitions between them. As illustrated above, it can be inspected via -the ``state`` property. - -The states are: - -* ``'idle'``: RunEngine is waiting for instructions. -* ``'running'``: RunEngine is executing instructions. -* ``'paused'``: RunEngine is waiting for user input. - -Suspender-related Methods -------------------------- - -.. automethod:: bluesky.run_engine.RunEngine.install_suspender - :noindex: - -.. automethod:: bluesky.run_engine.RunEngine.remove_suspender - :noindex: - -.. automethod:: bluesky.run_engine.RunEngine.clear_suspenders - :noindex: - -The RunEngine also has a ``suspenders`` property, a collection of the -currently-installed suspenders. - -Request Methods ---------------- - -This method is called when Ctrl+C is pressed or when a 'pause' Message is -processed. It can also be called by user-defined agents. See the next example. - -.. automethod:: bluesky.run_engine.RunEngine.request_pause - :noindex: - -This method is used by the ``PVSuspend*`` classes above. It can also be called -by user-defined agents. - -.. automethod:: bluesky.run_engine.RunEngine.request_suspend - :noindex: - - -Example: Requesting a pause from the asyncio event loop -------------------------------------------------------- - -Since the user does not have control of the prompt, calls to -``RE.request_pause`` must be planned in advance. Here is a example that pauses -the plan after 5 seconds. - -.. code-block:: python - - from bluesky.plan_stubs import null - - def loop_forever(): - "a silly plan" - while True: - yield from null() - - import asyncio - loop = asyncio.get_event_loop() - # Request a pause 5 seconds from now. - loop.call_later(5, RE.request_pause) - - # Execute the plan. - RE(loop_forever()) - - # Five seconds after ``call_later`` was run, the plan is paused. - # Observe that the RunEngine is in a 'paused' state. - RE.state - -Above, we passed ``True`` to ``RE.request_pause`` to request a deferred pause. - -Experimental: Record Interruptions -================================== - -In the analysis stage, it can be useful to know if and when a run was -interrupted. This experimental feature creates a special event stream -recording the time and nature of any interruptions. - -.. warning:: - - This is an experimental feature. It is tested but not yet widely used. It - might be changed or removed in the future. - -Activate this feature by setting - -.. code-block:: python - - RE.record_interruptions = True - -In this mode, the RunEngine emits a special event descriptor after opening a -new run. This name field in the descriptor is 'interruptions'. It has a single -data key: - -.. code-block:: python - - {'interruptions': {'dtype': 'string', - 'shape': None, - 'source': 'RunEngine'}} - -Each time the RunEngine is paused, suspended, or resumed during the run, an -Event document for that descriptor is created. The data payload -``event['data']['interruptions']`` is ``'pause'``, ``'suspend'``, or -``'resume'``. The associated time notes when the interruptions/resume was -processed. - -To see this in action, try this example: - -.. code-block:: python - - from bluesky.plans import count - from bluesky.preprocessors import pchain - from bluesky.plan_stubs import pause - from ophyd.sim import det - - RE.record_interruptions = True - - RE(pchain(count([det]), pause(), count([det])), print) - # ... RunEngine pauses - RE.resume() - -In the text that ``print`` dumps to the screen, look for the special -'interruptions' event descriptor and associated events. diff --git a/bluesky/_sources/state-machine.txt b/bluesky/_sources/state-machine.txt deleted file mode 100644 index f6add28926..0000000000 --- a/bluesky/_sources/state-machine.txt +++ /dev/null @@ -1,413 +0,0 @@ -Interruptions -************* - -The RunEngine can be safely interrupted and resumed. All plans get this -feature "for free." - -.. _pausing_interactively: - -Pausing Interactively -===================== - -.. note:: - - Looking for a quick refresher on pausing, resuming, or aborting - interactively? Skip to the :ref:`interactive_pause_summary`. - -While the RunEngine is executing a plan, it captures SIGINT (Ctrl+C). - -Pause Now: Ctrl+C twice ------------------------ - -.. code-block:: python - - In [1]: RE(scan([det], motor, -10, 10, 15), LiveTable([motor, det])) - +-----------+------------+------------+------------+ - | seq_num | time | motor | det | - +-----------+------------+------------+------------+ - | 1 | 07:21:29.2 | -10.000 | 0.000 | - | 2 | 07:21:29.3 | -8.571 | 0.000 | - | 3 | 07:21:29.4 | -7.143 | 0.000 | - ^C^C - Pausing... - In [2]: - -Before returning the prompt the user, the RunEngine ensures that all motors -that it has touched are stopped. It also performs any device-specific cleanup -defined in the device's (optional) ``pause()`` method. - -If execution is later resumed, the RunEngine will "rewind" through the plan to -the most recent :ref:`checkpoint `, the last safe place to restart. - -Pause Soon: Ctrl+C once ------------------------ - -Pause at the next :ref:`checkpoint `: typically, the next step in -a step scan. We call this "deferred pause." It avoids having to repeat any work -when the plan is resumed. - -Notice that this time when Ctrl+C (^C) is hit, the current step (4) is allowed -to complete before execution is paused. - -.. code-block:: python - - In [1]: RE(scan([det], motor, -10, 10, 15), LiveTable([motor, det])) - +-----------+------------+------------+------------+ - | seq_num | time | motor | det | - +-----------+------------+------------+------------+ - | 1 | 07:21:29.2 | -10.000 | 0.000 | - | 2 | 07:21:29.3 | -8.571 | 0.000 | - | 3 | 07:21:29.4 | -7.143 | 0.000 | - ^C - A 'deferred pause' has been requested. The RunEngine will pause at the next - checkpoint. To pause immediately, hit Ctrl+C again in the next 10 seconds. - Deferred pause acknowledged. Continuing to checkpoint. - | 4 | 07:21:29.5 | -5.728 | 0.000 | - Pausing... - In [2]: - -What to do after pausing ------------------------- - -After being paused, the RunEngine holds on to information that it might need in -order to resume later. It "knows" that it is in a paused state, and you can -check that at any time: - -.. code-block:: python - - In [2]: RE.state - Out[2]: 'paused' - - -During the pause, we can do anything: check readings, move motors, etc. It will -not allow you to execute a new plan until the current one is either resumed or -terminated. Your options are: - -Resume -^^^^^^ - -.. code-block:: python - - In [3]: RE.resume() - | 4 | 07:21:29.5 | -5.714 | 0.000 | - | 5 | 07:21:29.5 | -4.286 | 0.000 | - | 6 | 07:21:29.6 | -2.857 | 0.017 | - | 7 | 07:21:29.7 | -1.429 | 0.360 | - (etc.) - -Depending on the plan, it may "rewind" to safely continue on and ensure all -data is collected correctly. - -Abort -^^^^^ - -Allow the plan to perform any final cleanup. For example, some plans move -motors back to their starting positions. Mark the data as having been aborted, -so that this fact can be noted (if desired) in later analysis. All of the data -collected up this point will be saved regardless. - -From a paused state: - -.. code-block:: python - - In [3]: RE.abort() - Aborting... - Out[3]: ['8ef9388c-75d3-498c-a800-3b0bd24b88ed'] - -Stop -^^^^ - -``RE.stop()`` is functionally identical to ``RE.abort()``. The only -difference is that aborted runs are marked with ``exit_status: 'abort'`` -instead of ``exit_status: 'success'``. This distinction may be a useful -distinction during analysis`. - -Halt -^^^^ - -Aborting or stopping allows the plan to perform cleanup. We already mentioned -the example of a plan moving motors back to their starting positions at the -end. - -In some situations, you may wish to prevent the plan from doing *anything* ---- you want to halt immediately, skipping cleanup. For this, use -``RE.halt()``. - -.. _interactive_pause_summary: - -Summary -------- - -Interactively Interrupt Execution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -======================= =========== -Command Outcome -======================= =========== -Ctrl+C Pause soon. -Ctrl+C twice Pause now. -======================= =========== - -From a paused state -^^^^^^^^^^^^^^^^^^^ - -============== =========== -Command Outcome -============== =========== -RE.resume() Safely resume plan. -RE.abort() Perform cleanup. Mark as aborted. -RE.stop() Perform cleanup. Mark as success. -RE.halt() Do not perform cleanup --- just stop. -RE.state Check if 'paused' or 'idle'. -============== =========== - -Automated Suspension -==================== - -It can also be useful to interrupt execution automatically in response some -condition (e.g., shutter closed, beam dumped, temperature exceed some limit). -We use the word *suspension* to mean an unplanned pause initialized by some -agent running the background. The agent (a "suspender") monitors some condition -and, if it detects a problem, it suspends execution. When it detects that -conditions have returned to normal, it gives the RunEngine permission to resume -after some interval. This can operate unattended. - -.. ipython:: - :verbatim: - - In [1]: RE(scan([det], motor, -10, 10, 15), LiveTable([motor, det])) - +------------+-------------------+----------------+----------------+ - | seq_num | time | motor | det | - +------------+-------------------+----------------+----------------+ - | 1 | 16:46:08.953815 | 0.03 | 290.00 | - Suspending....To get prompt hit Ctrl-C to pause the scan - | 2 | 16:46:20.868445 | 0.09 | 279.00 | - | 3 | 16:46:29.077690 | 0.16 | 284.00 | - | 4 | 16:46:33.540643 | 0.23 | 278.00 | - +------------+-------------------+----------------+----------------+ - -A *suspended* plan does not return the prompt to the user. Like a paused plan, -it stops executing new instructions and rewinds to the most recent checkpoint. -But unlike a paused plan, it resumes execution automatically when conditions -return to normal. - -To take manual control of a suspended plan, pause it by hitting Ctrl+C twice. -You will be given the prompt. When conditions are good again, you may manually -resume using ``RE.resume()``. - -.. _installing_suspenders: - -Installing Suspenders ---------------------- - -Bluesky includes several "suspenders" that work with ophyd Signals to monitor -conditions and suspend execution. It's also possible to write suspenders -from scratch to monitor anything at all. - -We'll start with an example. - -Example: Suspend a plan if the beam current dips low -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This defines a suspender and installs it on the RunEngine. With this, plans -will be automatically suspended when the ``beam_current`` signal goes below 2 -and resume once it exceeds 3. - -.. code-block:: python - - from ophyd import EpicsSignal - from bluesky.suspenders import SuspendFloor - - beam_current = EpicsSignal('...PV string...') - sus = SuspendFloor(beam_current, 2, 3) - RE.install_suspender(sus) - -In the following example, the beam current dipped below 2 in the middle of -taking the second data point. It later recovered. - -.. ipython:: - :verbatim: - - In [6]: RE(my_scan) - +------------+-------------------+----------------+----------------+ - | seq_num | time | theta | sclr_chan4 | - +------------+-------------------+----------------+----------------+ - | 1 | 16:46:08.953815 | 0.03 | 290.00 | - Suspending....To get prompt hit Ctrl-C to pause the scan - | 2 | 16:46:20.868445 | 0.09 | 279.00 | - | 3 | 16:46:29.077690 | 0.16 | 284.00 | - | 4 | 16:46:33.540643 | 0.23 | 278.00 | - +------------+-------------------+----------------+----------------+ - -Notice that the plan was suspended and then resumed. When it resumed, it went -back to the last checkpoint and re-took the second data point cleanly. - -See the API documentation (follow the links in the table below) for other -suspender types and options, including a waiting period and cleanup -procedures to run pre-suspend and pre-resume. - -Built-in Suspenders -------------------- - -.. autosummary:: - :toctree: - :nosignatures: - - bluesky.suspenders.SuspendBoolHigh - bluesky.suspenders.SuspendBoolLow - bluesky.suspenders.SuspendFloor - bluesky.suspenders.SuspendCeil - bluesky.suspenders.SuspendInBand - bluesky.suspenders.SuspendOutBand - -.. _checkpoints: - -Checkpoints -=========== - -Plan are specified as a sequence of :ref:`messages `, granular -instructions like 'read' and 'set'. The messages can optionally include one -or more 'checkpoint' messages, indicating a place where it safe to resume after -an interruption. For example, checkpoints are placed before each step of a -:func:`bluesky.plans.scan`. - -Some experiments are not resumable: for example, the sample may be melting or -aging. Incorporating :func:`bluesky.plans.clear_checkpoint` in a plan makes it -un-resuming. If a pause or suspension are requested, the plan will abort -instead. - -.. note:: - - Some details about checkpoints and when they are allowed: - - It is not legal to create checkpoint in the middle of a data point (between - 'create' and 'save') Checkpoints are implicitly created after actions that - it is not safe to replay: staging a device, adding a monitor, or adding a - subscription. - -Planned Pauses -============== - -It's possible to write a custom *plan* that pauses at certain points, requiring -the user to manually resume or abort. - -See the :ref:`planned_pauses` subsection of the documentation on *Plans*. - -Associated RunEngine Interface -============================== - -State ------ - -The RunEngine has a state machine defining its phases of operation and the -allowed transitions between them. As illustrated above, it can be inspected via -the ``state`` property. - -The states are: - -* ``'idle'``: RunEngine is waiting for instructions. -* ``'running'``: RunEngine is executing instructions. -* ``'paused'``: RunEngine is waiting for user input. It can be - -Suspender-related Methods -------------------------- - -.. automethod:: bluesky.run_engine.RunEngine.install_suspender -.. automethod:: bluesky.run_engine.RunEngine.remove_suspender - -The RunEngine also has a ``suspenders`` property, a collection of the -currently-installed suspenders. - -Request Methods ---------------- - -This method is called when Ctrl+C is pressed or when a 'pause' Message is -processed. It can also be called by user-defined agents. See the next example. - -.. automethod:: bluesky.run_engine.RunEngine.request_pause - -This method is used by the ``PVSuspend*`` classes above. It can also be called -by user-defined agents. - -.. automethod:: bluesky.run_engine.RunEngine.request_suspend - - -Example: Requesting a pause from the asyncio event loop -------------------------------------------------------- - -Since the user does not control of the prompt, calls to ``RE.request_pause`` -must be planned in advance. Here is a example that pauses the plan after 5 -seconds. - -.. code-block:: python - - from bluesky.plans import null - - def loop_forever(): - "a silly plan" - while True: - yield from null() - - import asyncio - loop = asyncio.get_event_loop() - # Request a pause 5 seconds from now. - loop.call_later(5, RE.request_pause) - - # Execute the plan. - RE(loop_forever()) - - # Five seconds after ``call_later`` was run, the plan is paused. - # Observe that the RunEngine is in a 'paused' state. - RE.state - -Above, we passed ``True`` to ``RE.request_pause`` to request a deferred pause. - -Experimental: Record Interruptions -================================== - -In the analysis stage, it can be useful to know if and when a run was -interrupted. This experimental feature creates a special event stream -recording the time and nature of any interruptions. - -.. warning:: - - This is an experimental feature. It is tested but not yet widely used. It - might be changed or removed in the future. - -Activate this feature by setting - -.. code-block:: python - - RE.record_interruptions = True - -In this mode, the RunEngine emits a special event descriptor after opening a -new run. This name field in the descriptor is 'interruptions'. It has a single -data key: - -.. code-block:: python - - {'interruptions': {'dtype': 'string', - 'shape': None, - 'source': 'RunEngine'}} - -Each time the RunEngine is paused, suspended, or resumed during the run, an -Event document for that descriptor is created. The data payload -``event['data']['interruptions']`` is ``'pause'``, ``'suspend'``, or -``'resume'``. The associated time notes when the interruptions/resume was -processed. - -To see this in action, try this example: - -.. code-block:: python - - from bluesky.plans import pchain, count, pause - from bluesky.examples import det - - RE.record_interruptions = True - - RE(pchain(count([det]), pause(), count([det])), print) - # ... RunEngine pauses - RE.resume() - -In the text that ``print`` dumps to the screen, look for the special -'interruptions' event descriptor and associated events. diff --git a/bluesky/_sources/tutorial.rst.txt b/bluesky/_sources/tutorial.rst.txt deleted file mode 100644 index 137b7c045a..0000000000 --- a/bluesky/_sources/tutorial.rst.txt +++ /dev/null @@ -1,1915 +0,0 @@ -******** -Tutorial -******** - -Before You Begin -================ - -.. note:: - - NSLS-II deploys a free, public "sandbox" for trying the software in the - browser using Jupyter notebooks. There will be no need to install any - software, and you can skip the rest of this section. Go to - `https://try.nsls2.bnl.gov `_. - -* You will need Python 3.5 or newer. From a shell ("Terminal" on OSX, - "Command Prompt" on Windows), check your current Python version. - - .. code-block:: bash - - python3 --version - - If that version is less than 3.5, you must update it. - - We recommend install bluesky into a "virtual environment" so this - installation will not interfere with any existing Python software: - - .. code-block:: bash - - python3 -m venv ~/bluesky-tutorial - source ~/bluesky-tutorial/bin/activate - - Alternatively, if you are a - `conda `_ user, - you can create a conda environment: - - .. code-block:: bash - - conda create -n bluesky-tutorial "python>=3.5" - conda activate bluesky-tutorial - -* Install the latest versions of bluesky and ophyd. Also install the databroker - unless you plan to skip the sections about accessing saved data. If you want - to follow along with the visualization examples, install matplotlib and - PyQt5. Finally, install IPython (a Python interpreter designed by scientists - for scientists). - - .. code-block:: bash - - python3 -m pip install --upgrade bluesky ophyd databroker matplotlib pyqt5 ipython pyepics - - Alternatively, if you are a conda user and you prefer conda packages, you can - use: - - .. code-block:: bash - - conda install -c nsls2forge bluesky ophyd databroker matplotlib pyqt=5 ipython - -* Start IPython: - - .. code-block:: python - - ipython --matplotlib=qt5 - - The flag ``--matplotlib=qt5`` is necessary for live-updating plots to work. - - Or, if you wish you use bluesky from a Jupyter notebook, install a kernel like - so: - - .. code-block:: python - - ipython kernel install --user --name=bluesky-tutorial --display-name "Python (bluesky)" - - You may start Jupyter from any environment where it is already installed, or - install it in this environment alongside bluesky and run it from there: - - .. code-block:: python - - pip install notebook - jupyter notebook - -If you get lost or confused... -============================== - -...then we want to know! We have a friendly -`chat channel `_, or you can -`file a bug `_ to let us know -where our documentation could be made more clear. - -.. _tutorial_run_engine_setup: - -The RunEngine -============= - -Bluesky encodes an experimental procedure as a *plan*, a sequence of -atomic instructions. The *RunEngine* is an interpreter for plans. It lets -us focus on the logic of our experimental procedure while it handles important -technical details consistently: it communicates with hardware, monitors for -interruptions, organizes metadata and data, coordinates I/O, and ensures that -the hardware is left in a safe state at exit time. - -This separation of the executor (the RunEngine) from the instruction set (the -plan) pays off in several ways, as we will see in the examples that follow. - -.. note:: - - If you are a visiting user at a facility that runs bluesky, you can skip - this section and go straight to :ref:`common_experiments`. A RunEngine will - have already been configured for you. **If you ignore this and define your - own, you may be overriding pre-configured defaults, which can result in - data loss.** - - To check, type ``RE``. If a RunEngine has already been configured, you - should get something like: - - .. ipython:: - :verbatim: - - In [1]: RE - Out[1]: - - and you should skip the rest of this section. But if this gives you a - ``NameError``, you'll need to finish this section. - -Create a RunEngine: - -.. code-block:: python - - from bluesky import RunEngine - - RE = RunEngine({}) - -.. ipython:: python - :suppress: - - # for use in later demos - from bluesky import RunEngine - RE = RunEngine({}) - - -This RunEngine is ready to use --- but if you care about visualizing or saving -your data, there is more to do first.... - -During data acquisition, the RunEngine dispatches a live stream of metadata and -data to one or more consumers ("callbacks") for in-line data processing and -visualization and long-term storage. Example consumers include a live-updating -plot, a curve-fitting algorithm, a database, a message queue, or a file in your -preferred format. See :doc:`callbacks` for more detail. - -Prepare Live Visualization --------------------------- - -To start, let's use the all-purpose -:class:`~bluesky.callback.best_effort.BestEffortCallback`. - -.. code-block:: python - - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - - # Send all metadata/data captured to the BestEffortCallback. - RE.subscribe(bec) - - # Make plots update live while scans run. - from bluesky.utils import install_kicker - install_kicker() - -.. ipython:: python - :suppress: - - # for use in later demos - from bluesky.callbacks.best_effort import BestEffortCallback - bec = BestEffortCallback() - RE.subscribe(bec) - -The :class:`~bluesky.callback.best_effort.BestEffortCallback` will receive the -metadata/data in real time and produce plots and text, doing its best to -provide live feedback that strikes the right balance between "comprehensive" -and "overwhelming." - -For more tailored feedback, customized to a particular experiment, you may -configure custom callbacks. Start by reading up on :doc:`documents`, the -structure into which bluesky organized metadata and data captured during an -experiment. But for this tutorial and for many real experiments, the -:class:`~bluesky.callback.best_effort.BestEffortCallback` will suffice. - -Prepare Data Storage --------------------- - -.. _databroker_setup: - -The `databroker `_, a library developed in tandem -with bluesky, is an interface to searchable storage for metadata and data -generated by bluesky. For this tutorial, we will spin up a databroker backed by -temporary files. - -.. code-block:: python - - from databroker import Broker - db = Broker.named('temp') - - # Insert all metadata/data captured into db. - RE.subscribe(db.insert) - -.. ipython:: python - :suppress: - - # for use in later demos - from databroker import Broker - db = Broker.named('temp') - RE.subscribe(db.insert) - -.. warning:: - - **This example makes a temporary database. Do not use it for important - data.** The data will become difficult to access once Python exits or the - variable ``db`` is deleted. Running ``Broker.named('temp')`` a second time - creates a fresh, separate temporary database. - -Add a Progress Bar ------------------- - -Optionally, you can configure a progress bar. - -.. code-block:: python - - from bluesky.utils import ProgressBarManager - RE.waiting_hook = ProgressBarManager() - -See :doc:`progress-bar` for more details and configuration. - -Let's take some data! - -.. _common_experiments: - -Common Experiments ("Plans") -============================ - -Read Some Detectors -------------------- - -Begin with a very simple experiment: trigger and read some detectors. Bluesky -calls this "counting", a term of art inherited from the spectroscopy -community. - -For this tutorial, we will not assume that you have access to real detectors or -motors. In the examples that follow, we will use simulated hardware from -`ophyd `_, a library developed in tandem with -bluesky. In a :ref:`later section ` we will see what it looks -like to configure *real* hardware with ophyd. - -.. code-block:: python - - from ophyd.sim import det1, det2 # two simulated detectors - -Using the RunEngine, ``RE``, "count" the detectors: - -.. code-block:: python - - from bluesky.plans import count - dets = [det1, det2] # a list of any number of detectors - - RE(count(dets)) - -Demo: - -.. ipython:: python - :suppress: - - from bluesky.plans import count - from ophyd.sim import det1, det2 - dets = [det1, det2] - -.. ipython:: python - - RE(count(dets)) - -A key feature of bluesky is that these detectors could be simple photodiodes or -complex CCDs. All of those details are captured in the implementation of the -Device. From the point of view of bluesky, detectors are just Python objects -with certain methods. - -See :func:`~bluesky.plans.count` for more options. You can also view this -documentation in IPython by typing ``count?``. - -Try the following variations: - -.. code-block:: python - - # five consecutive readings - RE(count(dets, num=5)) - - # five sequential readings separated by a 1-second delay - RE(count(dets, num=5, delay=1)) - - # a variable delay - RE(count(dets, num=5, delay=[1, 2, 3, 4])) - -The :func:`~bluesky.plans.count` function (more precisely, Python *generator -function*) is an example of a *plan*, a sequence of instructions encoding an -experimental procedure. We'll get a better sense for why this design is useful -as we continue. Briefly, it empowers us to: - -* Introspect the instructions before we execute them, checking for accuracy, - safety, estimated duration, etc. -* Interrupt and "rewind" the instructions to a safe point to resume from, - both interactively and automatically (e.g. in the middle of the night). -* Reuse a generic set of instructions on different hardware. -* Modify the instructions programmatically, such as inserting a set of - baseline readings to be taken automatically before every experiment. - -.. warning:: - - Notice that entering a plan by itself doesn't do anything: - - .. ipython:: python - :suppress: - - from bluesky.plans import count - from ophyd.sim import det - dets = [det] - - .. ipython:: python - - count(dets, num=3) - - If we mean to *execute* the plan, we must use the RunEngine: - - .. ipython:: python - - RE(count(dets, num=3)) - -Scan ----- - -Use :func:`~bluesky.plans.scan` to scan ``motor`` from ``-1`` to ``1`` in ten -equally-spaced steps, wait for it to arrive at each step, and then trigger and -read some detector, ``det``. - -.. code-block:: python - - from ophyd.sim import det, motor - from bluesky.plans import scan - dets = [det] # just one in this case, but it could be more than one - - RE(scan(dets, motor, -1, 1, 10)) - -.. ipython:: python - :suppress: - - from bluesky.plans import scan - from ophyd.sim import det, motor - dets = [det] - -.. ipython:: python - - RE(scan(dets, motor, -1, 1, 10)) - -.. plot:: - - from bluesky.plans import scan - from ophyd.sim import det, motor - dets = [det] - RE(scan(dets, motor, -1, 1, 10)) - -Again, a key feature of bluesky is that ``motor`` may be any "movable" device, -including a temperature controller, a sample changer, or some pseudo-axis. From -the point of view of bluesky and the RunEngine, all of these are just objects -in Python with certain methods. - -In addition the producing a table and plot, the -:class:`~bluesky.callback.best_effort.BestEffortCallback` computes basic peak -statistics. Click on the plot area and press Shift+P ("peaks") to visualize -them over the data. The numbers (center of mass, max, etc.) are available in a -dictionary stashed as ``bec.peaks``. This is updated at the end of each run. -Of course, if peak statistics are not applicable, you may just ignore this -feature. - -Use :func:`~bluesky.plans.rel_scan` to scan from ``-1`` to ``1`` *relative to -the current position*. - -.. code-block:: python - - from bluesky.plans import rel_scan - - RE(rel_scan(dets, motor, -1, 1, 10)) - -Use :func:`~bluesky.plans.list_scan` to scan points with some arbitrary -spacing. - -.. code-block:: python - - from bluesky.plans import list_scan - - points = [1, 1, 2, 3, 5, 8, 13] - - RE(list_scan(dets, motor, points)) - -For a complete list of scan variations and other plans, see :doc:`plans`. - -.. _tutorial_multiple_motors: - -Scan Multiple Motors Together ------------------------------ - -There are two different things we might mean by the phrase "scan multiple -motors 'together'". In this case we mean that we move N motors along a line in -M steps, such as moving X and Y motors along a diagonal. In the other case, we -move N motors through an (M_1 x M_2 x ... x M_N) grid; that is addressed in the -next section. - -SPEC users may recognize this case as analogous to an "a2scan" or "d2scan", but -with an arbitrary number of dimensions, not just two. - -We'll use the same plans that we used in the previous section. (If you already -imported them, there is no need to do so again.) - -.. code-block:: python - - from bluesky.plans import scan, rel_scan - -We'll use two new motors and a new detector that is coupled to them via -a simulation. It simulates a 2D Gaussian peak centered at ``(0, 0)``. -Again, we emphasize that these "motors" could be anything that can be "set" -(temperature controller, pseudo-axis, sample changer). - -.. code-block:: python - - from ophyd.sim import det4, motor1, motor2 - dets = [det4] # just one in this case, but it could be more than one - -The plans :func:`~bluesky.plans.scan` and :func:`~bluesky.plans.rel_scan` -accept multiple motors. - -.. code-block:: python - - RE(scan(dets, - motor1, -1.5, 1.5, # scan motor1 from -1.5 to 1.5 - motor2, -0.1, 0.1, # ...while scanning motor2 from -0.1 to 0.1 - 11)) # ...both in 11 steps - -The line breaks are intended to make the command easier to visually parse. They -are not technically meaningful; you may take them or leave them. - -Demo: - -.. ipython:: python - :suppress: - - from bluesky.plans import scan - from ophyd.sim import det4, motor1, motor2 - dets = [det4] - -.. ipython:: python - - RE(scan(dets, - motor1, -1.5, 1.5, # scan motor1 from -1.5 to 1.5 - motor2, -0.1, 0.1, # ...while scanning motor2 from -0.1 to 0.1 - 11)) # ...both in 11 steps - -.. plot:: - - from bluesky.plans import scan - from ophyd.sim import det4, motor1, motor2 - dets = [det4] - RE(scan(dets, - motor1, -1.5, 1.5, # scan motor1 from -1.5 to 1.5 - motor2, -0.1, 0.1, # ...while scanning motor2 from -0.1 to 0.1 - 11)) # ...both in 11 steps - -This works for any number of motors, not just two. Try importing ``motor3`` -from ``ophyd.sim`` and running a 3-motor scan. - -To move motors along arbitrary trajectories instead of equally-spaced points, -use :func:`~bluesky.plans.list_scan` and :func:`~bluesky.plans.rel_list_scan`. - -.. code-block:: python - - from bluesky.plans import list_scan - - # Scan motor1 and motor2 jointly through a 5-point trajectory. - RE(list_scan(dets, motor1, [1, 1, 3, 5, 8], motor2, [25, 16, 9, 4, 1])) - -Demo: - -.. ipython:: python - :suppress: - - from bluesky.plans import list_scan - -.. ipython:: python - - RE(list_scan(dets, - motor1, [1, 1, 3, 5, 8], - motor2, [25, 16, 9, 4, 1])) - -.. plot:: - - from bluesky.plans import list_scan - from ophyd.sim import det4, motor1, motor2 - dets = [det4] - RE(list_scan(dets, - motor1, [1, 1, 3, 5, 8], - motor2, [25, 16, 9, 4, 1])) - -Scan Multiple Motors in a Grid ------------------------------- - -In this case scan N motors through an N-dimensional rectangular grid. We'll use -the same simulated hardware as in the previous section: - -.. code-block:: python - - from ophyd.sim import det4, motor1, motor2 - dets = [det4] # just one in this case, but it could be more than one - -We'll use a new plan, named :func:`~bluesky.plans.grid_scan`. - -.. code-block:: python - - from bluesky.plans import grid_scan - -Let's start with a 3x5x5 grid. - -.. code-block:: python - - RE(grid_scan(dets, - motor1, -1.5, 1.5, 3, # scan motor1 from -1.5 to 1.5 in 3 steps - motor2, -0.1, 0.1, 5, # scan motor2 from -0.1 to 0.1 in 5 steps - motor3, 10, -10, 5)) # scan motor3 from 10 to -10 in 5 steps - -The order of the motors controls how the grid is traversed. The "slowest" axis -comes first. Numpy users will appreciate that this is consistent with numpy's -convention for indexing multidimensional arrays. - -The optional parameter ``snake_axes`` can be used to control which motors' -trajectories "snake" back and forth. A snake-like path is usually more -efficient, but it is not suitable for certain hardware, so it is disabled by -default. To enable snaking for specific axes, give a list like -``snake_axes=[motor2]``. Since the first (slowest) axis is only traversed -once, it is not eligible to be included in ``snake_axes``. As a convenience, -you may use ``snake_axes=True`` to enable snaking for all except that first -axis. - -.. plot:: - - from bluesky.simulators import plot_raster_path - from ophyd.sim import motor1, motor2, det - from bluesky.plans import grid_scan - import matplotlib.pyplot as plt - - snaked = grid_scan([det], motor1, -5, 5, 10, motor2, -7, 7, 15, snake_axes=True) - not_snaked = grid_scan([det], motor1, -5, 5, 10, motor2, -7, 7, 15) - - fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True) - plot_raster_path(snaked, 'motor1', 'motor2', probe_size=.3, ax=ax1) - plot_raster_path(not_snaked, 'motor1', 'motor2', probe_size=.3, ax=ax2) - ax1.set_title('True') - ax2.set_title('False') - ax1.set_xlim(-6, 6) - ax2.set_xlim(-6, 6) - -Demo: - -.. ipython:: python - :suppress: - - from bluesky.plans import grid_scan - from ophyd.sim import motor1, motor2, det4 - dets = [det4] - -.. ipython:: python - - RE(grid_scan(dets, - motor1, -1.5, 1.5, 3, # scan motor1 from -1.5 to 1.5 in 3 steps - motor2, -0.1, 0.1, 5)) # scan motor2 from -0.1 to 0.1 in 5 steps - -.. plot:: - - from bluesky.plans import grid_scan - from ophyd.sim import motor1, motor2, det4 - dets = [det4] - RE(grid_scan(dets, - motor1, -1.5, 1.5, 3, # scan motor1 from -1.5 to 1.5 in 3 steps - motor2, -0.1, 0.1, 5)) # scan motor2 from -0.1 to 0.1 in 5 steps - -To move motors along arbitrary trajectories instead of equally-spaced points, -use :func:`~bluesky.plans.list_grid_scan` and -:func:`~bluesky.plans.rel_list_grid_scan`. - -.. code-block:: python - - from bluesky.plans import list_grid_scan - - RE(list_grid_scan(dets, - motor1, [1, 1, 2, 3, 5], - motor2, [25, 16, 9])) - -Demo: - -.. ipython:: python - :suppress: - - from bluesky.plans import list_grid_scan - -.. ipython:: python - - RE(list_grid_scan(dets, - motor1, [1, 1, 2, 3, 5], - motor2, [25, 16, 9])) - -.. plot:: - - from bluesky.plans import list_grid_scan - from ophyd.sim import det4, motor1, motor2 - dets = [det4] - RE(list_grid_scan(dets, - motor1, [1, 1, 2, 3, 5], - motor2, [25, 16, 9])) - -See :ref:`multi-dimensional_scans` to handle more specialized cases, including -combinations of :func:`~bluesky.plans.scan`-like and -:func:`~bluesky.plans.grid_scan`-like movement. - -More generally, the :doc:`plans` documentation includes more exotic -trajectories, such as spirals, and plans with adaptive logic, such as -efficient peak-finders. - -Aside: Access Saved Data -======================== - -At this point it is natural to wonder, "How do I access my saved data?" -From the point of view of *bluesky*, that's really not bluesky's concern, but -it's a reasonable question, so we'll address a typical scenario. - -.. note:: - - This section presumes that you are using the databroker. (We configured - one in :ref:`an earlier section of this tutorial `.) - You don't have to use the databroker to use bluesky; it's just - one convenient way to capture the metadata and data generated by the - RunEngine. - -Very briefly, you can access saved data by referring to a dataset (a "run") by -its unique ID, which is returned by the RunEngine at collection time. - -.. ipython:: python - - from bluesky.plans import count - from ophyd.sim import det - uid, = RE(count([det], num=3)) - header = db[uid] - -Alternatively, perhaps more conveniently, you can access it by recency: - -.. ipython:: python - - header = db[-1] # meaning '1 run ago', i.e. the most recent run - -.. note:: - - We assumed above that the plan generated one "run" (dataset), which is - typical for simple plans like :func:`~bluesky.plans.count`. In the - *general* case, a plan can generate multiple runs, returning multiple uids, - which in turn causes ``db`` to return a list of headers, not just one. - - .. code-block:: python - - uids = RE(some_plan(...)) - headers = db[uids] # list of Headers - -Most of the useful metadata is in this dictionary: - -.. ipython:: python - - header.start - -And the ("primary") stream of data is accessible like so: - -.. ipython:: python - - header.table() # return a table (a pandas.DataFrame) - -From here we refer to the -`databroker tutorial `_. - -.. _tutorial_simple_customization: - -Simple Customization -==================== - -Save Some Typing with 'Partial' -------------------------------- - -Suppose we nearly always use the same detector(s) and we tire of typing out -``count([det])``. We can write a custom variant of :func:`~bluesky.plans.count` -using a built-in function provided by Python itself, :func:`functools.partial`. - -.. code-block:: python - - from functools import partial - from bluesky.plans import count - from ophyd.sim import det - - my_count = partial(count, [det]) - RE(my_count()) # equivalent to RE(count([det])) - - # Additional arguments to my_count() are passed through to count(). - RE(my_count(num=3, delay=1)) - -Plans in Series ---------------- - -A custom plan can dispatch out to other plans using the Python syntax -``yield from``. (See :ref:`appendix ` if you want to know -why.) Examples: - -.. code-block:: python - - from bluesky.plans import scan - - def coarse_and_fine(detectors, motor, start, stop): - "Scan from 'start' to 'stop' in 10 steps and then again in 100 steps." - yield from scan(detectors, motor, start, stop, 10) - yield from scan(detectors, motor, start, stop, 100) - - RE(coarse_and_fine(dets, motor, -1, 1)) - -All of the plans introduced thus far, which we imported from -:mod:`bluesky.plans`, generate data sets ("runs"). Plans in the -:mod:`bluesky.plan_stubs` module do smaller operations. They can be used alone -or combined to build custom plans. - -The :func:`~bluesky.plan_stubs.mv` plan moves one or more devices and waits for -them all to arrive. - -.. code-block:: python - - from bluesky.plan_stubs import mv - from ophyd.sim import motor1, motor2 - - # Move motor1 to 1 and motor2 to 10, simultaneously. Wait for both to arrive. - RE(mv(motor1, 1, motor2, 10)) - -We can combine :func:`~bluesky.plan_stubs.mv` and :func:`~bluesky.plans.count` -into one plan like so: - -.. code-block:: python - - def move_then_count(): - "Move motor1 and motor2 into position; then count det." - yield from mv(motor1, 1, motor2, 10) - yield from count(dets) - - RE(move_then_count()) - -It's very important to remember the ``yield from``. The following plan does -nothing at all! (The plans inside it will be *defined* but never executed.) - -.. code-block:: python - - # WRONG EXAMPLE! - - def oops(): - "Forgot 'yield from'!" - mv(motor1, 1, motor2, 10) - count(dets) - -Much richer customization is possible, but we'll leave that for a -:ref:`a later section of this tutorial `. See also the -complete list of :ref:`plan stubs `. - -.. warning:: - - **Never put ``RE(...)`` inside a loop or a function. You should always call - it directly --- typed by the user at the terminal --- and only once.** - - You might be tempted to write a script like this: - - .. code-block:: python - - from bluesky.plans import scan - from ophyd.sim import motor, det - - # Don't do this! - for j in [1, 2, 3]: - print(j, 'steps') - RE(scan([det], motor, 5, 10, j))) - - Or a function like this: - - .. code-block:: python - - # Don't do this! - def bad_function(): - for j in [1, 2, 3]: - print(j, 'steps') - RE(scan([det], motor, 5, 10, j))) - - But, instead, you should do this: - - .. code-block:: python - - from bluesky.plans import scan - from ophyd.sim import motor, det - - def good_plan(): - for j in [1, 2, 3]: - print(j, 'steps') - yield from scan([det], motor, 5, 10, j) - - RE(my_plan()) - - If you try to hide ``RE`` inside a function, someone later might - use that function inside another function, and now we're entering and - exiting the RunEngine multiple times from a single prompt. This can lead - to unexpected behavior, especially around handling interruptions and - errors. - - To indulge a musical metaphor, the plan is the sheet music, the hardware is - the orchestra, and the RunEngine is the conductor. There should be only - one conductor and she needs to run whole show, start to finish. - -"Baseline" Readings (and other Supplemental Data) -================================================= - -In addition to the detector(s) and motor(s) of primary interest during an -experiment, it is commonly useful to take a snapshot ("baseline reading") of -other hardware. This information is typically used to check consistency over -time. ("Is the temperature of the sample mount roughly the same as it was last -week?") Ideally, we'd like to *automatically* capture readings from these -devices during all future experiments without any extra thought or typing per -experiment. Bluesky provides a specific solution for this. - -Configure ---------- - -.. note:: - - If you are visiting user at a facility that runs bluesky, you may not need - to do this configuration, and you can skip the next subsection just below - --- :ref:`choose_baseline_devices`. - - You can type ``sd`` to check. If you get something like: - - .. ipython:: - :verbatim: - - In [1]: sd - Out[1]: SupplementalData(baseline=[], monitors=[], flyers=[]) - - you should skip this configuration. - -Before we begin, we have to do a little more RunEngine configuration, like what -we did in the :ref:`tutorial_run_engine_setup` section with ``RE.subscribe``. - -.. code-block:: python - - from bluesky.preprocessors import SupplementalData - - sd = SupplementalData() - RE.preprocessors.append(sd) - -.. ipython:: python - :suppress: - - from bluesky.preprocessors import SupplementalData - sd = SupplementalData() - RE.preprocessors.append(sd) - -.. _choose_baseline_devices: - -Choose "Baseline" Devices -------------------------- - -We'll choose the detectors/motors that we want to be read automatically at the -beginning and end of each dataset ("run"). If you are using a shared -configuration, this also might already have been done, so you should check the -content of ``sd.baseline`` before altering it. - -.. ipython:: python - - sd.baseline # currently empty - -Suppose that we want to take baseline readings from three detectors and two -motors. We'll import a handful of simulated devices for this purpose, put them -into a list, and assign ``sd.baseline``. - -.. ipython:: python - - from ophyd.sim import det1, det2, det3, motor1, motor2 - sd.baseline = [det1, det2, det3, motor1, motor2] - -Notice that we can put a mixture of detectors and motors in this list. It -doesn't matter to bluesky that some are movable and some are not because it's -just going to be *reading* them, and both detectors and motors can be read. - -Use ---- - -Now we can just do a scan with the detector and motor of primary interest. The -RunEngine will automatically take baseline readings before and after each run. -Demo: - -.. ipython:: python - - from ophyd.sim import det, motor - from bluesky.plans import scan - RE(scan([det], motor, -1, 1, 5)) - -We can clear or update the list of baseline detectors at any time. - -.. ipython:: python - - sd.baseline = [] - -As an aside, this is one place where the design of bluesky really pays off. By -separating the executor (the RunEngine) from the instruction sets (the plans) -it's easy to apply global configuration without updating every plan -individually. - -Access Baseline Data --------------------- - -If you access the data from our baseline scan, you might think that the -baseline data is missing! - -.. ipython:: python - - header = db[-1] - header.table() - -Looking again at the output when we executed this scan, notice these lines: - -.. code-block:: none - - New stream: 'baseline' - ... - New stream: 'primary' - -By default, ``header.table()`` gives us the "primary" data stream: - -.. ipython:: python - - header.table('primary') # same result as header.table() - -We can access other streams by name. - -.. ipython:: python - - header.table('baseline') - -A list of the stream names in a given run is available as -``header.stream_names``. From here we refer to the -`databroker tutorial `_. - -Other Supplemental Data ------------------------ - -Above, we used ``sd.baseline``. There is also ``sd.monitors`` for signals to -monitor asynchronously during a run and ``sd.flyers`` for devices to "fly-scan" -during a run. See :ref:`supplemental_data` for details. - -.. _tutorial_pause_resume_suspend: - -Pause, Resume, Suspend -====================== - -Interactive Pause & Resume --------------------------- - -Sometimes it is convenient to pause data collection, check on some things, and -then either resume from where you left off or quit. The RunEngine makes it -possible to do this cleanly and safely on *any* plan, including user-defined -plans, with minimal effort by the user. Of course, experiments on systems -that evolve with time can't be arbitrarily paused and resumed. It's up to the -user to know that and use this feature only when applicable. - -Take this example, a step scan over ten points. - -.. code-block:: python - - from ophyd.sim import det, motor - from bluesky.plans import scan - - motor.delay = 1 # simulate slow motor movement - RE(scan([det], motor, 1, 10, 10)) - -Demo: - -.. ipython:: - :verbatim: - - In [1]: RE(scan([det], motor, 1, 10, 10)) - Transient Scan ID: 1 Time: 2018/02/12 12:40:36 - Persistent Unique Scan ID: 'c5db9bb4-fb7f-49f4-948b-72fb716d1f67' - New stream: 'primary' - +-----------+------------+------------+------------+ - | seq_num | time | motor | det | - +-----------+------------+------------+------------+ - | 1 | 12:40:37.6 | 1.000 | 0.607 | - | 2 | 12:40:38.7 | 2.000 | 0.135 | - | 3 | 12:40:39.7 | 3.000 | 0.011 | - -At this point we decide to hit **Ctrl+C** (SIGINT). The RunEngine will catch -this signal and react like so. We will examine this output piece by piece. - -.. code-block:: none - - ^C - A 'deferred pause' has been requested.The RunEngine will pause at the next - checkpoint. To pause immediately, hit Ctrl+C again in the next 10 seconds. - Deferred pause acknowledged. Continuing to checkpoint. - <...a few seconds later...> - | 4 | 12:40:40.7 | 4.000 | 0.000 | - Pausing... - - --------------------------------------------------------------------------- - RunEngineInterrupted Traceback (most recent call last) - in () - ----> 1 RE(scan([det], motor, 1, 10, 10)) - <...snipped details...> - - RunEngineInterrupted: - Your RunEngine is entering a paused state. These are your options for changing - the state of the RunEngine: - RE.resume() Resume the plan. - RE.abort() Perform cleanup, then kill plan. Mark exit_stats='aborted'. - RE.stop() Perform cleanup, then kill plan. Mark exit_status='success'. - RE.halt() Emergency Stop: Do not perform cleanup --- just stop. - -When it pauses, the RunEngine immediately tells all Devices that it has touched -so far to "stop". (Devices define what that means to them in their ``stop()`` -method.) This is not a replacement for proper equipment protection; it is just -a convenience. - -Now, at our leisure, we may: - -* pause to think -* investigate the state of our hardware, such as the detector's exposure time -* turn on more verbose logging (see :doc:`debugging`) -* decide whether to stop here or resume - -Suppose we decide to resume. The RunEngine will pick up from the last -"checkpoint". Typically, this means beginning of each step in a scan, but -plans may specify checkpoints anywhere they like. - -.. ipython:: - :verbatim: - - In [13]: RE.resume() - | 5 | 12:40:50.1 | 5.000 | 0.000 | - | 6 | 12:40:51.1 | 6.000 | 0.000 | - | 7 | 12:40:52.1 | 7.000 | 0.000 | - | 8 | 12:40:53.1 | 8.000 | 0.000 | - | 9 | 12:40:54.1 | 9.000 | 0.000 | - | 10 | 12:40:55.1 | 10.000 | 0.000 | - +-----------+------------+------------+------------+ - generator scan ['c5db9bb4'] (scan num: 1) - -The scan has completed successfully. - -If you go back and read the output from when we hit Ctrl+C, you will notice -that the RunEngine didn't pause immediately: it finished the current step of -the scan first. Quoting an excerpt from the demo above: - -.. code-block:: none - - ^C - A 'deferred pause' has been requested.The RunEngine will pause at the next - checkpoint. To pause immediately, hit Ctrl+C again in the next 10 seconds. - Deferred pause acknowledged. Continuing to checkpoint. - <...a few seconds later...> - | 4 | 12:40:40.7 | 4.000 | 0.000 | - Pausing... - -Observe that hitting Ctrl+C *twice* pauses immediately, without waiting to -finish the current step. - -.. code-block:: none - - In [2]: RE(scan([det], motor, 1, 10, 10)) - Transient Scan ID: 2 Time: 2018/02/15 12:31:14 - Persistent Unique Scan ID: 'b342448f-6a64-4f26-91a6-37f559cb5537' - New stream: 'primary' - +-----------+------------+------------+------------+ - | seq_num | time | motor | det | - +-----------+------------+------------+------------+ - | 1 | 12:31:15.8 | 1.000 | 0.607 | - | 2 | 12:31:16.8 | 2.000 | 0.135 | - | 3 | 12:31:17.8 | 3.000 | 0.011 | - ^C^C - Pausing... - -When resumed, the RunEngine will *rewind* to the last checkpoint (the beginning -of the fourth step in the scan) and repeat instructions as needed. - -Quoting again from the demo, notice that ``RE.resume()`` was only one of our -options. If we decide not to continue we can quit in three different ways: - -.. code-block:: none - - Your RunEngine is entering a paused state. These are your options for changing - the state of the RunEngine: - RE.resume() Resume the plan. - RE.abort() Perform cleanup, then kill plan. Mark exit_stats='aborted'. - RE.stop() Perform cleanup, then kill plan. Mark exit_status='success'. - RE.halt() Emergency Stop: Do not perform cleanup --- just stop. - -"Aborting" and "stopping" are almost the same thing: they just record different -metadata about why the experiment was ended. Both signal to the plan that it -should end early, but they still let it specify more instructions so that it -can "clean up." For example, a :func:`~bluesky.plans.rel_scan` moves the motor -back to its starting position before quitting. - -In rare cases, if we are worried that the plan's cleanup procedure might be -dangerous, we can "halt". Halting circumvents the cleanup instructions. - -Try executing ``RE(scan([det], motor, 1, 10, 10))``, pausing, and exiting in -these various ways. Observe that the RunEngine won't let you run a new plan -until you have resolved the paused plan using one of these methods. - -Automated Suspend & Resume --------------------------- - -The RunEngine can be configured in advance to *automatically* pause and resume -in response to external signals. To distinguish automatic pause/resume from -interactive, user-initiated pause and resume, we call this behavior -"suspending." - -For details, see :ref:`suspenders`. - -.. _tutorial_metadata: - -Metadata -======== - -If users pass extra keyword arguments to ``RE``, they are interpreted as -metadata - -.. code-block:: python - - RE(count([det]), user='Dan', mood='skeptical') - RE(count([det]), user='Dan', mood='optimistic') - -and they can be used for searching later: - -.. code-block:: python - - headers = db(user='Dan') - headers = db(mood='skeptical') - -Metadata can also be added *persistently* (i.e. applied to all future runs -until removed) by editing the dictionary ``RE.md``. - -.. code-block:: python - - RE.md - RE.md['user'] = 'Dan' - -No need to specify ``user`` every time now.... - -.. code-block:: python - - RE(count([det])) # automatically includes user='Dan' - -The key can be temporarily overridden: - -.. code-block:: python - - RE(count([det]), user='Tom') # overrides the setting in RE.md, just once - -or deleted: - -.. code-block:: python - - del RE.md['user'] - -In addition to any user-provided metadata, the RunEngine, the devices, and the -plan capture some metadata automatically. For more see, :doc:`metadata`. - -Simulate and Introspect Plans -============================= - -We have referred to a *plan* as a "sequence of instructions encoding an -experimental procedure." But what's inside a plan really? Bluesky calls each -atomic instruction inside a plan a *message*. Handling the messages directly -is only necessary when debugging or doing unusually deep customization, but -it's helpful to see them at least once before moving on to more practical -tools. - -Try printing out every message in a couple simple plans: - -.. code-block:: python - - from bluesky.plans import count - from ophyd.sim import det - - for msg in count([]): - print(msg) - - for msg in count([det]): - print(msg) - -See the :doc:`msg` section for more. - -Bluesky includes some tools for producing more useful, human-readable summaries -to answer the question, "What will this plan do?" - -.. ipython:: python - - from bluesky.simulators import summarize_plan - from bluesky.plans import count, rel_scan - from ophyd.sim import det, motor - # Count a detector 3 times. - summarize_plan(count([det], 3)) - # A 3-step scan. - summarize_plan(rel_scan([det], motor, -1, 1, 3)) - -For more possibilities, see :doc:`simulation`. - -.. _tutorial_device: - -Devices -======= - -Theory ------- - -The notion of a "Device" serves two goals: - -* Provide a **standard interface** to all hardware for the sake of generality - and code reuse. -* **Logically group** individual signals into composite "Devices" that can be - read together, as a unit, and configured in a coordinated way. Provide a - human-readable name to this group, with an eye toward later data analysis. - -In bluesky's view of the world, there are only three different kinds of devices -used in data acquisition. - -* Some devices can be **read**. This includes simple points detectors that - produce a single number and large CCD detectors that produce big arrays. -* Some devices can be both **read and set**. Setting a motor physically moves - it to a new position. Setting a temperature controller impels it to gradually - change its temperature. Setting the exposure time on some detector promptly - updates its configuration. -* Some devices produce data at a rate too high to be read out in real time, and - instead **buffer their data externally** in separate hardware or software - until it can be read out. - -Bluesky interacts with all devices via a :doc:`specified interface `. -Each device is represented by a Python object with certain methods and -attributes (with names like ``read`` and ``set``). Some of these methods are -asynchronous, such as ``set``, which allows for the concurrent movement of -multiple devices. - -Implementation --------------- - -`Ophyd `_, a Python library that was -developed in tandem with bluesky, implements this interface for devices that -speak `EPICS `_. But bluesky is not tied to -ophyd or EPICS specifically: any Python object may be used, so long as it -provides the specified methods and attributes that bluesky expects. For -example, an experimental implementation of the bluesky interface for LabView -has been written. And the simulated hardware that we have been using in this -tutorial is all based on pure-Python constructs unconnected from hardware or -any specific hardware control protocol. - -To get a flavor for what it looks like to configure hardware in ophyd, -connecting to an EPICS motor looks like this: - -.. code-block:: python - - from ophyd import EpicsMotor - - nano_top_x = EpicsMotor('XF:31ID-ES{Dif:Nano-Ax:TopX}Mtr', name='nano_top_x') - -We have provided both the machine-readable address of the motor on the network, -``'XF:31ID-ES{Dif:Nano-Ax:TopX}Mtr'`` (in EPICS jargon, the "PV" for -"Process Variable"), and a human-readable name, ``'nano_top_x'``, which will be -used to label the data generated by this motor. When it comes time to analyze -the data, we will be grateful to be dealing with the human-readable label. - -The ``EpicsMotor`` device is a logical grouping of many signals. The most -important are the readback (actual position) and setpoint (target position). -All of the signals are summarized thus. The details here aren't important at -this stage: the take-away message is, "There is a lot of stuff to keep track of -about a motor, and a Device helpfully groups that stuff for us." - -.. code-block:: none - - In [3]: nano_top_x.summary() - data keys (* hints) - ------------------- - *nano_top_x - nano_top_x_user_setpoint - - read attrs - ---------- - user_readback EpicsSignalRO ('nano_top_x') - user_setpoint EpicsSignal ('nano_top_x_user_setpoint') - - config keys - ----------- - nano_top_x_acceleration - nano_top_x_motor_egu - nano_top_x_user_offset - nano_top_x_user_offset_dir - nano_top_x_velocity - - configuration attrs - ---------- - motor_egu EpicsSignal ('nano_top_x_motor_egu') - velocity EpicsSignal ('nano_top_x_velocity') - acceleration EpicsSignal ('nano_top_x_acceleration') - user_offset EpicsSignal ('nano_top_x_user_offset') - user_offset_dir EpicsSignal ('nano_top_x_user_offset_dir') - - Unused attrs - ------------ - offset_freeze_switch EpicsSignal ('nano_top_x_offset_freeze_switch') - set_use_switch EpicsSignal ('nano_top_x_set_use_switch') - motor_is_moving EpicsSignalRO ('nano_top_x_motor_is_moving') - motor_done_move EpicsSignalRO ('nano_top_x_motor_done_move') - high_limit_switch EpicsSignal ('nano_top_x_high_limit_switch') - low_limit_switch EpicsSignal ('nano_top_x_low_limit_switch') - direction_of_travel EpicsSignal ('nano_top_x_direction_of_travel') - motor_stop EpicsSignal ('nano_top_x_motor_stop') - home_forward EpicsSignal ('nano_top_x_home_forward') - home_reverse EpicsSignal ('nano_top_x_home_reverse') - - -.. _tutorial_custom_plans: - -Write Custom Plans -================== - -As mentioned in the :ref:`tutorial_simple_customization` section above, the -"pre-assembled" plans with :func:`~bluesky.plans.count` and -:func:`~bluesky.plans.scan` are built from smaller "plan stubs". We can -mix and match the "stubs" and/or "pre-assembled" plans to build custom plans. - -There are many of plan stubs, so it's convenient to import the whole module and -work with that. - -.. code-block:: python - - import bluesky.plan_stubs as bps - -Move in Parallel ----------------- - -Before writing a custom plan to coordinate the motion of multiple devices, -consider whether your use case could be addressed with one of the built-in -:ref:`multi-dimensional_scans`. - -We previously introduced the :func:`~bluesky.plan_stubs.mv` plan that moves one -or more devices and waits for them all to arrive. There is also -:func:`~bluesky.plans.mvr` for moving *relative* to the current position. - -.. code-block:: python - - from ophyd.sim import motor1, motor2 - - # Move motor1 to 1 and motor2 10 units in the positive direction relative - # to their current positions. Wait for both to arrive. - RE(bps.mvr(motor1, 1, motor2, 10)) - -Some scenarios require more low-level control over when the waiting occurs. -For these, we employ :func:`~bluesky.plan_stubs.wait` and -:func:`~bluesky.plan_stubs.abs_set` ("absolute set") or -:func:`~bluesky.plan_stubs.rel_set` ("relative set"). - -Here is a scenario that does require a custom solution: we want to set several -motors in motion at once, including multiple fast motors and one slow motor. We -want to wait for the fast motors to arrive, print a message, then wait for the -slow motor to arrive, and print a second message. - -.. code-block:: python - - def staggered_wait(fast_motors, slow_motor): - # Start all the motors, fast and slow, moving at once. - # Put all the fast_motors in one group... - for motor in fast_motors: - yield from bps.abs_set(motor, 5, group='A') - # ...but put the slow motor is separate group. - yield from bps.abs_set(slow_motor, 5, group='B') - - # Wait for all the fast motors. - print('Waiting on the fast motors.') - yield from bps.wait('A') - print('Fast motors are in place. Just waiting on the slow one now.') - - # Then wait for the slow motor. - yield from bps.wait('B') - print('Slow motor is in place.') - -Sleeping (Timed Delays) ------------------------ - -.. note:: - - If you need to wait for your motor to finish moving, temperature to finish - equilibrating, or shutter to finish opening, inserting delays into plans - isn't the best way to do that. It should be the *Device's* business to - report accurately when it is done, including any extra padding for settling - or equilibration. On some devices, such as ``EpicsMotor``, this can be - configured like ``motor.settle_time = 3``. - -For timed delays, bluesky has a special plan, which allows the RunEngine to -continue its business during the sleep. - -.. code-block:: python - - def sleepy_plan(motor, positions): - "Step a motor through a list of positions with 1-second delays between steps.") - for position in positions: - yield from bps.mv(motor, position) - yield from bps.sleep(1) - -**You should always use this plan, *never* Python's built-in function -:func:`time.sleep`.** Why? -The RunEngine uses an event loop to concurrently manage many tasks. It assumes -that none of those tasks blocks for very long. (A good figure for "very long" -is 0.2 seconds.) Therefore, you should never incorporate long blocking function -calls in your plan, such as ``time.sleep(1)``. - -.. _tutorial_capture_data: - -Capture Data ------------- - -.. ipython:: python - :suppress: - - # Define a examples that we will use interactively below. - import bluesky.plan_stubs as bps - def one_run_one_event(detectors): - yield from bps.open_run() - yield from bps.trigger_and_read(detectors) - yield from bps.close_run() - def one_run_multi_events(detectors, num): - yield from bps.open_run() - for i in range(num): - yield from bps.trigger_and_read(detectors) - yield from bps.close_run() - def multi_runs_multi_events(detectors, num, num_runs): - for i in range(num_runs): - yield from one_run_multi_events(detectors, num) - -Any plan that generates data must include instructions for grouping readings -into *Events* (i.e. rows in a table) and grouping those Events into *Runs* -(datasets that are given a "scan ID"). This is best explained by example. - -.. code-block:: python - - import bluesky.plan_stubs as bps - - def one_run_one_event(detectors): - # Declare the beginning of a new run. - yield from bps.open_run() - - # Trigger each detector and wait for triggering to complete. - # Then read the detectors and bundle these readings into an Event - # (i.e. one row in a table.) - yield from bps.trigger_and_read(detectors) - - # Declare the end of the run. - yield from bps.close_run() - -Execute the plan like so: - -.. ipython:: python - - RE(one_run_one_event([det1, det2])) - -We observe: - -* one table (one Run) -* one row (one Event) -* two columns (a column for each detector) - -Here's the same plan again, with :func:`~bluesky.plan_stubs.trigger_and_read` -moved inside a for loop. - -.. code-block:: python - - def one_run_multi_events(detectors, num): - yield from bps.open_run() - - for i in range(num): - yield from bps.trigger_and_read(detectors) - - yield from bps.close_run() - -Execute the plan like so: - -.. ipython:: python - - RE(one_run_multi_events([det1, det2], 3)) - -We observe: - -* one table (one Run) -* three rows (three Events) -* two columns (a column for each detector) - -Finally, add another loop re-using ``one_run_multi_events`` inside that loop. - -.. code-block:: python - - def multi_runs_multi_events(detectors, num, num_runs): - for i in range(num_runs): - yield from one_run_multi_events(detectors, num) - -.. ipython:: python - - RE(multi_runs_multi_events([det1, det2], num=3, num_runs=2)) - -We observe: - -* two tables (two Runs) -* three rows (three Events) -* two columns (a column for each detector) - -We also notice that the return value output from the RunEngine is a tuple with -two unique IDs, one per Run generated by this plan. - -In order to focus on the scope of an Event and a Run, we have left out an -important detail, addressed in the next section, which may be necessary to -incorporate before trying these plans on real devices. - -Stage and Unstage ------------------ - -Complex devices often require some preliminary setup before they can be used -for data collection, moving them from a resting state into a state where they -are ready to acquire data. Bluesky accommodates this in a general way by -allowing every Device to implement an optional ``stage()`` method, with a -corresponding ``unstage()`` method. Plans should stage every device that they -touch exactly once and unstage every device at the end. If a Device does not -have a ``stage()`` method the RunEngine will just skip over it. - -Revising our simplest example above, ``one_run_one_event``, - -.. code-block:: python - - import bluesky.plan_stubs as bps - - def one_run_one_event(detectors): - yield from bps.open_run() - yield from bps.trigger_and_read(detectors) - yield from bps.close_run() - -we incorporate staging like so: - -.. code-block:: python - - def one_run_one_event(detectors): - - # 'Stage' every device. - for det in detectors: - yield from bps.stage(det) - - yield from bps.open_run() - yield from bps.trigger_and_read(detectors) - yield from bps.close_run() - - # 'Unstage' every device. - for det in detectors: - yield from bps.unstage(det) - -This is starting to get verbose. At this point, we might want to accept some -additional complexity in exchange for brevity --- and some assurance that we -don't forget to use these plans in matching pairs. To that end, this plan is -equivalent: - -.. code-block:: python - - import bluesky.preprocessors as bpp - - def one_run_one_event(detectors): - - @bpp.stage_decorator(detectors) - def inner(): - yield from bps.open_run() - yield from bps.trigger_and_read(detectors) - yield from bps.close_run() - - return (yield from inner()) - -The :func:`~bluesky.preprocessors.stage_decorator` is a *plan preprocessor*, a -plan which consumes another plan and modifies its instructions. In this case, -it adds inserts 'stage' and 'unstage' messages, supplanting -:func:`~bluesky.plan_stubs.stage` and :func:`~bluesky.plan_stubs.unstage`. We -can trim the verbosity down yet more by employing -:func:`~bluesky.preprocessors.run_decorator`, supplanting -:func:`~bluesky.plan_stubs.open_run` and :func:`~bluesky.plan_stubs.close_run`. -The result: - -.. code-block:: python - - import bluesky.preprocessors as bpp - - def one_run_one_event(detectors): - - @bpp.stage_decorator(detectors) - @bpp.run_decorator() - def inner(): - yield from bps.trigger_and_read(detectors) - - return (yield from inner()) - -Incidentally, recall that we have already encountered a preprocessor in this -tutorial, in the section on baseline readings. -:class:`~bluesky.preprocessors.SupplementalData` is a preprocessor. - -.. _tutorial_plan_metadata: - -Add Metadata ------------- - -To make it easier to search for data generated by the plan and to inspect what -was done afterward, we should include some metadata. We create a dictionary and -pass it to :func:`~bluesky.preprocessors.run_decorator` (or, in the more -verbose formulation, to :func:`~bluesky.plan_stubs.open_run`). The RunEngine -will combine this metadata with any information provided by the user, as shown -in the :ref:`the earlier section on metadata `. - -.. code-block:: python - - def one_run_one_event(detectors): - - md = { - # Human-friendly names of detector Devices (useful for searching) - 'detectors': [det.name for det in detectors], - - # The Python 'repr's each argument to the plan - 'plan_args': {'detectors': list(map(repr, detectors))}, - - # The name of this plan - 'plan_name': 'one_run_one_event', - } - - @bpp.stage_decorator(detectors) - @bpp.run_decorator(md) - def inner(): - yield from bps.trigger_and_read(detectors) - - return (yield from inner()) - -.. warning:: - - The values in the metadata dictionary must be strings, numbers, - lists/arrays, or dictionaries only. Metadata cannot contain arbitrary - Python types because downstream consumers (like databases) do not know what - to do with those and will error. - -To be polite, we should allow the user to override this metadata. All of -bluesky's "pre-assembled" plans (:func:`~bluesky.plans.count`, -:func:`~bluesky.plans.scan`, etc.) provide an optional ``md`` argument for this -purpose, implemented like so: - -.. code-block:: python - - def one_run_one_event(detectors, md=None): - - _md = { - 'detectors': [det.name for det in detectors], - 'plan_args': {'detectors': list(map(repr, detectors))}, - 'plan_name': 'one_run_one_event', - } - - # If a key exists in md, it overwrites the default in _md. - _md.update(md or {}) - - @bpp.stage_decorator(detectors) - @bpp.run_decorator(_md) - def inner(): - yield from bps.trigger_and_read(detectors) - - return (yield from inner()) - -Add "Hints" in Metadata ------------------------ - -The metadata dictionary may optionally include a key named ``'hints'``. This -key has special significance to the -:class:`~bluesky.callback.best_effort.BestEffortCallback` and potentially -other downstream consumers, which use it to try to infer useful ways to -present the data. Currently, it solves two specific problems. - -1. Narrow the potentially large set of readings to a manageable number of most - important ones that fit into a table. -2. Identify the dimensionality of the data (1D scan? 2D grid? N-D grid?) and - the dependent and independent parameters, for visualization and peak-fitting - purposes. - -It's up to each device to address (1). The plan has no role in that. -Each device has an optional ``hints`` attribute with a value like -``{'fields': [...]}`` to answer the question, "Of all the readings you -produce, what are the names of the most important ones?" - -We need the plan to help us with (2). Only the plan can sort out which devices -are being employed as "independent" axes and which are being measured as -dependent variables. This isn't clear just from looking at the Devices alone -because any given movable device can be used as an axis or as a "detector" -depending on the context --- ``count([motor])`` is a perfectly valid thing to -do! - -The schema of the plan's hint metadata is: - -.. code-block:: python - - {'dimensions': [([, ...], ), - ([, ...], ), - ... - ]} - -Examples: - -.. code-block:: python - - # a 1-D scan over x - {'dimensions': [(['x'], 'primary')]} - - # a 2-D grid_scan over x and y - {'dimensions': [(['x'], 'primary'), - (['y'], 'primary')]} - - # a scan moving x and y together along a diagonal - {'dimensions': [(['x', 'y'], 'primary')]} - - # a 1-D scan over temperature, represented in C and K units - {'dimensions': [(['C', 'K'], 'primary')]} - - # a 1-D scan over energy, as measured in energy and diffractometer position - {'dimensions': [(['E', 'dcm'], 'primary')]} - - # special case: a sequence of readings where the independent axis is just time - {'dimensions': [(['time'], 'primary')]} - -Each entry in the outer list represents one independent dimension. A dimension -might be represented by multiple fields, either from different devices moved in -a coordinated fashion by the plan (``['x', 'y']``), presented as fully redundant -information from one device (``['C', 'K']``), or coupled information from two -sub-devices (``['E', 'dcm']``). - -The second element in each entry is the stream name: ``'primary'`` in every -example above. This should correspond to the ``name`` passed into -:func:`~bluesky.plan_stubs.trigger_and_read` or -:func:`~bluesky.plan_stubs.create` inside the plan. The default name is -``primary``. - -Putting it all together, the plan asks the device(s) being used as independent -axes for their important field(s) and builds a list of dimensions like so: - -.. code-block:: python - - dimensions = [(motor.hints['fields'], 'primary')] - -We must account for the fact that ``hints`` is optional. A given Device -might not have a ``hints`` attribute at all and, even if it does, the -hints might not contain the ``'fields'`` key that we are interested in. This -pattern silently omits the dimensions hint if the necessary information is not -provided by the Device: - -.. code-block:: python - - def scan(..., md=None): - _md = {...} - _md.update(md or {}) - - try: - dimensions = [(motor.hints['fields'], 'primary')] - except (AttributeError, KeyError): - pass - else: - _md['hints'].setdefault('dimensions', dimensions) - - ... - -Finally, by using ``setdefault``, we have allowed user to override these hints -if they know better by passing in ``scan(..., md={'hints': ...})``. - -.. _tutorial_adaptive: - -Adaptive Logic in a Plan ------------------------- - -Two-way communication is possible between the generator and the RunEngine. -For example, the :func:`~trigger_and_read` plan responds with its readings. We -can use it to make an on-the-fly decision about whether to continue or stop. - -.. code-block:: python - - import bluesky.preprocessors as bpp - import bluesky.plan_stubs as bps - from ophyd.sim import det, motor - def conditional_break(threshold): - """Set, trigger, read until the detector reads intensity < threshold""" - - @bpp.stage_decorator([det, motor]) - @bpp.run_decorator() - def inner(): - i = 0 - while True: - yield from bps.mv(motor, i) - readings = yield from bps.trigger_and_read([det]) - if readings['det']['value'] < threshold: - break - i += 1 - return (yield from inner()) - -.. ipython:: python - :suppress: - - import bluesky.preprocessors as bpp - import bluesky.plan_stubs as bps - from bluesky import Msg - from ophyd.sim import det, motor - def conditional_break(threshold): - def inner(): - i = 0 - while True: - yield from bps.mv(motor, i) - readings = yield from bps.trigger_and_read([det]) - if readings['det']['value'] < threshold: - break - i += 1 - # Decorators do not work in IPython sphinx directive! - # Using wrapper instead... - return (yield from bpp.stage_wrapper(bpp.run_wrapper(inner()), [det, motor])) - -Demo: - -.. ipython:: python - - RE(conditional_break(0.2)) - -The important line in this example is - -.. code-block:: python - - reading = yield from bps.trigger_and_read([det]) - -The action proceeds like this: - -1. The plan yields a 'read' message to the RunEngine. -2. The RunEngine reads the detector. -3. The RunEngine sends that reading *back to the plan*, and that response is - assigned to the variable ``reading``. - -The response, ``reading``, is formatted like: - -.. code-block:: python - - {: {'value': , 'timestamp': }, ...} - -For a detailed technical description of the messages and their responses, -see :ref:`msg`. - -.. _tutorial_exception_handling: - -Plan "Cleanup" (Exception Handling) ------------------------------------ - -If an exception is raised, the RunEngine gives the plan the opportunity to -catch the exception and either handle it or merely yield some "clean up" -messages before re-raising the exception and killing plan execution. (Recall -this from :ref:`tutorial_pause_resume_suspend` above.) - -This is the general idea: - -.. code-block:: python - - # This example is illustrative, but it is not completely correct. - # Use `finalize_wrapper` instead (or read its source code). - - def plan_with_cleanup(): - def main_plan(): - # do stuff... - - def cleanup_plan(): - # do other stuff... - - try: - yield from main_plan() - finally: - # Do this even if an Exception is raised. - yield from cleanup_plan() - -The exception in question may originate from the plan itself or from the -RunEngine when it attempts to execute a given command. - -The :func:`~bluesky.preprocessors.finalize_wrapper` preprocessor provides a -succinct and fully correct way of applying this general pattern. - -.. code-block:: python - - import bluesky.preprocessors as bpp - - def plan_with_cleanup(): - yield from bpp.finalize_wrapper(main_plan(), cleanup_plan()) - -Further Reading ---------------- - -* :ref:`per_step_hook` -* Specifying checkpoints (TODO) -* Monitoring (TODO) -* Fly Scanning (TODO) -* :ref:`Pausing from a plan ` -* :func:`~bluesky.plans.input_plan` (TODO) -* Going deeper than :func:`~bluesky.plan_stubs.trigger_and_read` (TODO) diff --git a/bluesky/_sources/utils.rst.txt b/bluesky/_sources/utils.rst.txt deleted file mode 100644 index 417a59dfea..0000000000 --- a/bluesky/_sources/utils.rst.txt +++ /dev/null @@ -1,87 +0,0 @@ - -Utility classes and functions -============================= - -.. automodule:: bluesky.utils - - -Msg ---- -.. autosummary:: - :nosignatures: - :toctree: generated - - Msg - - -Persistent metadata -------------------- - -To maintain a peristent set of meta-data between Python sessions -we include a dictionary duck-type based on `zict.Func`. - -.. autosummary:: - :nosignatures: - :toctree: generated - - PersistentDict - PersistentDict.directory - - - -Internal exceptions -------------------- - -We define a number of `Exception` sub-classes for internal signaling. - -.. autosummary:: - :nosignatures: - :toctree: generated - - RunEngineControlException - RequestAbort - RequestStop - RunEngineInterrupted - NoReplayAllowed - IllegalMessageSequence - FailedPause - FailedStatus - InvalidCommand - PlanHalt - RampFail - - -Progress bars -------------- - -These are used by the RunEngine to display progress bars and -are the clients of the :obj:`~ophyd.status.MoveStatus.watch` API - - - -.. autosummary:: - :nosignatures: - :toctree: generated - - ProgressBar - ProgressBar.update - ProgressBar.draw - ProgressBar.clear - - ProgressBarManager - - -During tasks ------------- - -These objects encapsulate what the RunEngine should do on its thread while -waiting for the plan to complete in the background thread - -.. autosummary:: - :nosignatures: - :toctree: generated - - DuringTask - DuringTask.block - - DefaultDuringTask diff --git a/bluesky/_static/basic.css b/bluesky/_static/basic.css deleted file mode 100644 index 24a49f09b5..0000000000 --- a/bluesky/_static/basic.css +++ /dev/null @@ -1,856 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; - margin-right: 0.5em; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0.5em; - content: ":"; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/bluesky/_static/css/badge_only.css b/bluesky/_static/css/badge_only.css deleted file mode 100644 index e380325bc6..0000000000 --- a/bluesky/_static/css/badge_only.css +++ /dev/null @@ -1 +0,0 @@ -.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/bluesky/_static/css/fonts/Roboto-Slab-Bold.woff b/bluesky/_static/css/fonts/Roboto-Slab-Bold.woff deleted file mode 100644 index 6cb6000018..0000000000 Binary files a/bluesky/_static/css/fonts/Roboto-Slab-Bold.woff and /dev/null differ diff --git a/bluesky/_static/css/fonts/Roboto-Slab-Bold.woff2 b/bluesky/_static/css/fonts/Roboto-Slab-Bold.woff2 deleted file mode 100644 index 7059e23142..0000000000 Binary files a/bluesky/_static/css/fonts/Roboto-Slab-Bold.woff2 and /dev/null differ diff --git a/bluesky/_static/css/fonts/Roboto-Slab-Regular.woff b/bluesky/_static/css/fonts/Roboto-Slab-Regular.woff deleted file mode 100644 index f815f63f99..0000000000 Binary files a/bluesky/_static/css/fonts/Roboto-Slab-Regular.woff and /dev/null differ diff --git a/bluesky/_static/css/fonts/Roboto-Slab-Regular.woff2 b/bluesky/_static/css/fonts/Roboto-Slab-Regular.woff2 deleted file mode 100644 index f2c76e5bda..0000000000 Binary files a/bluesky/_static/css/fonts/Roboto-Slab-Regular.woff2 and /dev/null differ diff --git a/bluesky/_static/css/fonts/fontawesome-webfont.eot b/bluesky/_static/css/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca953..0000000000 Binary files a/bluesky/_static/css/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/bluesky/_static/css/fonts/fontawesome-webfont.svg b/bluesky/_static/css/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e53..0000000000 --- a/bluesky/_static/css/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bluesky/_static/css/fonts/fontawesome-webfont.ttf b/bluesky/_static/css/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2fa1..0000000000 Binary files a/bluesky/_static/css/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/bluesky/_static/css/fonts/fontawesome-webfont.woff b/bluesky/_static/css/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4b0..0000000000 Binary files a/bluesky/_static/css/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/bluesky/_static/css/fonts/fontawesome-webfont.woff2 b/bluesky/_static/css/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc6040..0000000000 Binary files a/bluesky/_static/css/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-bold-italic.woff b/bluesky/_static/css/fonts/lato-bold-italic.woff deleted file mode 100644 index 88ad05b9ff..0000000000 Binary files a/bluesky/_static/css/fonts/lato-bold-italic.woff and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-bold-italic.woff2 b/bluesky/_static/css/fonts/lato-bold-italic.woff2 deleted file mode 100644 index c4e3d804b5..0000000000 Binary files a/bluesky/_static/css/fonts/lato-bold-italic.woff2 and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-bold.woff b/bluesky/_static/css/fonts/lato-bold.woff deleted file mode 100644 index c6dff51f06..0000000000 Binary files a/bluesky/_static/css/fonts/lato-bold.woff and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-bold.woff2 b/bluesky/_static/css/fonts/lato-bold.woff2 deleted file mode 100644 index bb195043cf..0000000000 Binary files a/bluesky/_static/css/fonts/lato-bold.woff2 and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-normal-italic.woff b/bluesky/_static/css/fonts/lato-normal-italic.woff deleted file mode 100644 index 76114bc033..0000000000 Binary files a/bluesky/_static/css/fonts/lato-normal-italic.woff and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-normal-italic.woff2 b/bluesky/_static/css/fonts/lato-normal-italic.woff2 deleted file mode 100644 index 3404f37e2e..0000000000 Binary files a/bluesky/_static/css/fonts/lato-normal-italic.woff2 and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-normal.woff b/bluesky/_static/css/fonts/lato-normal.woff deleted file mode 100644 index ae1307ff5f..0000000000 Binary files a/bluesky/_static/css/fonts/lato-normal.woff and /dev/null differ diff --git a/bluesky/_static/css/fonts/lato-normal.woff2 b/bluesky/_static/css/fonts/lato-normal.woff2 deleted file mode 100644 index 3bf9843328..0000000000 Binary files a/bluesky/_static/css/fonts/lato-normal.woff2 and /dev/null differ diff --git a/bluesky/_static/css/theme.css b/bluesky/_static/css/theme.css deleted file mode 100644 index 8cd4f101a9..0000000000 --- a/bluesky/_static/css/theme.css +++ /dev/null @@ -1,4 +0,0 @@ -html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li span.toctree-expand:before,.wy-nav-top a,.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li span.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li span.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li span.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li span.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li span.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li span.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li span.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li span.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p.caption .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.btn .wy-menu-vertical li span.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p.caption .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.nav .wy-menu-vertical li span.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p.caption .btn .headerlink,.rst-content p.caption .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li span.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol li,.rst-content ol.arabic li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content ol.arabic li p:last-child,.rst-content ol.arabic li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover span.toctree-expand,.wy-menu-vertical li.on a:hover span.toctree-expand{color:grey}.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover span.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp{user-select:none;pointer-events:none}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink{visibility:hidden;font-size:14px}.rst-content .code-block-caption .headerlink:after,.rst-content .toctree-wrapper>p.caption .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after{content:"\f0c1";font-family:FontAwesome}.rst-content .code-block-caption:hover .headerlink:after,.rst-content .toctree-wrapper>p.caption:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .hlist{width:100%}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl dt span.classifier:before{content:" : "}html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.field-list>dt:after,html.writer-html5 .rst-content dl.footnote>dt:after{content:":"}html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.footnote>dt>span.brackets{margin-right:.5rem}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{font-style:italic}html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.footnote>dd p,html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code,html.writer-html4 .rst-content dl:not(.docutils) tt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/bluesky/_static/doctools.js b/bluesky/_static/doctools.js deleted file mode 100644 index 7d88f807dc..0000000000 --- a/bluesky/_static/doctools.js +++ /dev/null @@ -1,316 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keydown(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box, textarea, dropdown or button - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' - && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey - && !event.shiftKey) { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/bluesky/_static/documentation_options.js b/bluesky/_static/documentation_options.js deleted file mode 100644 index a7ae4534f5..0000000000 --- a/bluesky/_static/documentation_options.js +++ /dev/null @@ -1,12 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '1.6.7.post2+g888716e', - LANGUAGE: 'None', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false -}; \ No newline at end of file diff --git a/bluesky/_static/file.png b/bluesky/_static/file.png deleted file mode 100644 index a858a410e4..0000000000 Binary files a/bluesky/_static/file.png and /dev/null differ diff --git a/bluesky/_static/fonts/FontAwesome.otf b/bluesky/_static/fonts/FontAwesome.otf deleted file mode 100644 index 401ec0f36e..0000000000 Binary files a/bluesky/_static/fonts/FontAwesome.otf and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bold.eot b/bluesky/_static/fonts/Lato/lato-bold.eot deleted file mode 100644 index 3361183a41..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bold.eot and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bold.ttf b/bluesky/_static/fonts/Lato/lato-bold.ttf deleted file mode 100644 index 29f691d5ed..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bold.ttf and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bold.woff b/bluesky/_static/fonts/Lato/lato-bold.woff deleted file mode 100644 index c6dff51f06..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bold.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bold.woff2 b/bluesky/_static/fonts/Lato/lato-bold.woff2 deleted file mode 100644 index bb195043cf..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bold.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bolditalic.eot b/bluesky/_static/fonts/Lato/lato-bolditalic.eot deleted file mode 100644 index 3d4154936b..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bolditalic.eot and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bolditalic.ttf b/bluesky/_static/fonts/Lato/lato-bolditalic.ttf deleted file mode 100644 index f402040b3e..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bolditalic.ttf and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bolditalic.woff b/bluesky/_static/fonts/Lato/lato-bolditalic.woff deleted file mode 100644 index 88ad05b9ff..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bolditalic.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-bolditalic.woff2 b/bluesky/_static/fonts/Lato/lato-bolditalic.woff2 deleted file mode 100644 index c4e3d804b5..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-bolditalic.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-italic.eot b/bluesky/_static/fonts/Lato/lato-italic.eot deleted file mode 100644 index 3f826421a1..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-italic.eot and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-italic.ttf b/bluesky/_static/fonts/Lato/lato-italic.ttf deleted file mode 100644 index b4bfc9b24a..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-italic.ttf and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-italic.woff b/bluesky/_static/fonts/Lato/lato-italic.woff deleted file mode 100644 index 76114bc033..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-italic.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-italic.woff2 b/bluesky/_static/fonts/Lato/lato-italic.woff2 deleted file mode 100644 index 3404f37e2e..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-italic.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-regular.eot b/bluesky/_static/fonts/Lato/lato-regular.eot deleted file mode 100644 index 11e3f2a5f0..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-regular.eot and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-regular.ttf b/bluesky/_static/fonts/Lato/lato-regular.ttf deleted file mode 100644 index 74decd9ebb..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-regular.ttf and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-regular.woff b/bluesky/_static/fonts/Lato/lato-regular.woff deleted file mode 100644 index ae1307ff5f..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-regular.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Lato/lato-regular.woff2 b/bluesky/_static/fonts/Lato/lato-regular.woff2 deleted file mode 100644 index 3bf9843328..0000000000 Binary files a/bluesky/_static/fonts/Lato/lato-regular.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Bold.woff b/bluesky/_static/fonts/Roboto-Slab-Bold.woff deleted file mode 100644 index 6cb6000018..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Bold.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Bold.woff2 b/bluesky/_static/fonts/Roboto-Slab-Bold.woff2 deleted file mode 100644 index 7059e23142..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Bold.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Light.woff b/bluesky/_static/fonts/Roboto-Slab-Light.woff deleted file mode 100644 index 337d287116..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Light.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Light.woff2 b/bluesky/_static/fonts/Roboto-Slab-Light.woff2 deleted file mode 100644 index 20398aff31..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Light.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Regular.woff b/bluesky/_static/fonts/Roboto-Slab-Regular.woff deleted file mode 100644 index f815f63f99..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Regular.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Regular.woff2 b/bluesky/_static/fonts/Roboto-Slab-Regular.woff2 deleted file mode 100644 index f2c76e5bda..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Regular.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Thin.woff b/bluesky/_static/fonts/Roboto-Slab-Thin.woff deleted file mode 100644 index 6b30ea630d..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Thin.woff and /dev/null differ diff --git a/bluesky/_static/fonts/Roboto-Slab-Thin.woff2 b/bluesky/_static/fonts/Roboto-Slab-Thin.woff2 deleted file mode 100644 index 328f5bb042..0000000000 Binary files a/bluesky/_static/fonts/Roboto-Slab-Thin.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot deleted file mode 100644 index 79dc8efed3..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf deleted file mode 100644 index df5d1df273..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff deleted file mode 100644 index 6cb6000018..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 deleted file mode 100644 index 7059e23142..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot deleted file mode 100644 index 2f7ca78a1e..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf deleted file mode 100644 index eb52a79073..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff deleted file mode 100644 index f815f63f99..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff and /dev/null differ diff --git a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 b/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 deleted file mode 100644 index f2c76e5bda..0000000000 Binary files a/bluesky/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/fontawesome-webfont.eot b/bluesky/_static/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca953..0000000000 Binary files a/bluesky/_static/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/bluesky/_static/fonts/fontawesome-webfont.svg b/bluesky/_static/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e53..0000000000 --- a/bluesky/_static/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bluesky/_static/fonts/fontawesome-webfont.ttf b/bluesky/_static/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2fa1..0000000000 Binary files a/bluesky/_static/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/bluesky/_static/fonts/fontawesome-webfont.woff b/bluesky/_static/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4b0..0000000000 Binary files a/bluesky/_static/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/bluesky/_static/fonts/fontawesome-webfont.woff2 b/bluesky/_static/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc6040..0000000000 Binary files a/bluesky/_static/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/lato-bold-italic.woff b/bluesky/_static/fonts/lato-bold-italic.woff deleted file mode 100644 index 88ad05b9ff..0000000000 Binary files a/bluesky/_static/fonts/lato-bold-italic.woff and /dev/null differ diff --git a/bluesky/_static/fonts/lato-bold-italic.woff2 b/bluesky/_static/fonts/lato-bold-italic.woff2 deleted file mode 100644 index c4e3d804b5..0000000000 Binary files a/bluesky/_static/fonts/lato-bold-italic.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/lato-bold.woff b/bluesky/_static/fonts/lato-bold.woff deleted file mode 100644 index c6dff51f06..0000000000 Binary files a/bluesky/_static/fonts/lato-bold.woff and /dev/null differ diff --git a/bluesky/_static/fonts/lato-bold.woff2 b/bluesky/_static/fonts/lato-bold.woff2 deleted file mode 100644 index bb195043cf..0000000000 Binary files a/bluesky/_static/fonts/lato-bold.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/lato-normal-italic.woff b/bluesky/_static/fonts/lato-normal-italic.woff deleted file mode 100644 index 76114bc033..0000000000 Binary files a/bluesky/_static/fonts/lato-normal-italic.woff and /dev/null differ diff --git a/bluesky/_static/fonts/lato-normal-italic.woff2 b/bluesky/_static/fonts/lato-normal-italic.woff2 deleted file mode 100644 index 3404f37e2e..0000000000 Binary files a/bluesky/_static/fonts/lato-normal-italic.woff2 and /dev/null differ diff --git a/bluesky/_static/fonts/lato-normal.woff b/bluesky/_static/fonts/lato-normal.woff deleted file mode 100644 index ae1307ff5f..0000000000 Binary files a/bluesky/_static/fonts/lato-normal.woff and /dev/null differ diff --git a/bluesky/_static/fonts/lato-normal.woff2 b/bluesky/_static/fonts/lato-normal.woff2 deleted file mode 100644 index 3bf9843328..0000000000 Binary files a/bluesky/_static/fonts/lato-normal.woff2 and /dev/null differ diff --git a/bluesky/_static/jquery-1.11.1.js b/bluesky/_static/jquery-1.11.1.js deleted file mode 100644 index d4b67f7e6c..0000000000 --- a/bluesky/_static/jquery-1.11.1.js +++ /dev/null @@ -1,10308 +0,0 @@ -/*! - * jQuery JavaScript Library v1.11.1 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2014-05-01T17:42Z - */ - -(function( global, factory ) { - - if ( typeof module === "object" && typeof module.exports === "object" ) { - // For CommonJS and CommonJS-like environments where a proper window is present, - // execute the factory and get jQuery - // For environments that do not inherently posses a window with a document - // (such as Node.js), expose a jQuery-making factory as module.exports - // This accentuates the need for the creation of a real window - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Can't do this because several apps including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -// Support: Firefox 18+ -// - -var deletedIds = []; - -var slice = deletedIds.slice; - -var concat = deletedIds.concat; - -var push = deletedIds.push; - -var indexOf = deletedIds.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var support = {}; - - - -var - version = "1.11.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android<4.1, IE<9 - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num != null ? - - // Return just the one element from the set - ( num < 0 ? this[ num + this.length ] : this[ num ] ) : - - // Return all the elements in a clean array - slice.call( this ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - ret.context = this.context; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: deletedIds.sort, - splice: deletedIds.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var src, copyIsArray, copy, name, options, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - /* jshint eqeqeq: false */ - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - // parseFloat NaNs numeric-cast false positives (null|true|false|"") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - isPlainObject: function( obj ) { - var key; - - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Support: IE<9 - // Handle iteration over inherited properties before own properties. - if ( support.ownLast ) { - for ( key in obj ) { - return hasOwn.call( obj, key ); - } - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call(obj) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && jQuery.trim( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var value, - i = 0, - length = obj.length, - isArray = isArraylike( obj ); - - if ( args ) { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } - } - - return obj; - }, - - // Support: Android<4.1, IE<9 - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArraylike( Object(arr) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( indexOf ) { - return indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - while ( j < len ) { - first[ i++ ] = second[ j++ ]; - } - - // Support: IE<9 - // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) - if ( len !== len ) { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, - i = 0, - length = elems.length, - isArray = isArraylike( elems ), - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var args, proxy, tmp; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: function() { - return +( new Date() ); - }, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -}); - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -function isArraylike( obj ) { - var length = obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - if ( obj.nodeType === 1 && length ) { - return true; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v1.10.19 - * http://sizzlejs.com/ - * - * Copyright 2013 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2014-04-18 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + -(new Date()), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // General-purpose constants - strundefined = typeof undefined, - MAX_NEGATIVE = 1 << 31, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf if we can't use a native one - indexOf = arr.indexOf || function( elem ) { - var i = 0, - len = this.length; - for ( ; i < len; i++ ) { - if ( this[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + characterEncoding + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - rescape = /'|\\/g, - - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }; - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var match, elem, m, nodeType, - // QSA vars - i, groups, old, nid, newContext, newSelector; - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - - context = context || document; - results = results || []; - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { - return []; - } - - if ( documentIsHTML && !seed ) { - - // Shortcuts - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document (jQuery #6963) - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // QSA path - if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - nid = old = expando; - newContext = context; - newSelector = nodeType === 9 && selector; - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - groups = tokenize( selector ); - - if ( (old = context.getAttribute("id")) ) { - nid = old.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - nid = "[id='" + nid + "'] "; - - i = groups.length; - while ( i-- ) { - groups[i] = nid + toSelector( groups[i] ); - } - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; - newSelector = groups.join(","); - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {Function(string, Object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result - */ -function assert( fn ) { - var div = document.createElement("div"); - - try { - return !!fn( div ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( div.parentNode ) { - div.parentNode.removeChild( div ); - } - // release memory in IE - div = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = attrs.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - ( ~b.sourceIndex || MAX_NEGATIVE ) - - ( ~a.sourceIndex || MAX_NEGATIVE ); - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== strundefined && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, - doc = node ? node.ownerDocument || node : preferredDoc, - parent = doc.defaultView; - - // If no document and documentElement is available, return - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Set our document - document = doc; - docElem = doc.documentElement; - - // Support tests - documentIsHTML = !isXML( doc ); - - // Support: IE>8 - // If iframe document is assigned to "document" variable and if iframe has been reloaded, - // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 - // IE6-8 do not support the defaultView property so parent will be undefined - if ( parent && parent !== parent.top ) { - // IE11 does not have attachEvent, so all must suffer - if ( parent.addEventListener ) { - parent.addEventListener( "unload", function() { - setDocument(); - }, false ); - } else if ( parent.attachEvent ) { - parent.attachEvent( "onunload", function() { - setDocument(); - }); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) - support.attributes = assert(function( div ) { - div.className = "i"; - return !div.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( div ) { - div.appendChild( doc.createComment("") ); - return !div.getElementsByTagName("*").length; - }); - - // Check if getElementsByClassName can be trusted - support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { - div.innerHTML = "
"; - - // Support: Safari<4 - // Catch class over-caching - div.firstChild.className = "i"; - // Support: Opera<10 - // Catch gEBCN failure to find non-leading classes - return div.getElementsByClassName("i").length === 2; - }); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( div ) { - docElem.appendChild( div ).id = expando; - return !doc.getElementsByName || !doc.getElementsByName( expando ).length; - }); - - // ID find and filter - if ( support.getById ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && documentIsHTML ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [ m ] : []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - } else { - // Support: IE6/7 - // getElementById is not reliable as a find shortcut - delete Expr.find["ID"]; - - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var elem, - tmp = [], - i = 0, - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See http://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - div.innerHTML = ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( div.querySelectorAll("[msallowclip^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = doc.createElement("input"); - input.setAttribute( "type", "hidden" ); - div.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( div.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully does not implement inclusive descendent - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === doc ? -1 : - b === doc ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return doc; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, outerCache, node, diff, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || (parent[ expando ] = {}); - cache = outerCache[ type ] || []; - nodeIndex = cache[0] === dirruns && cache[1]; - diff = cache[0] === dirruns && cache[2]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - // Use previously-cached element index if available - } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { - diff = cache[1]; - - // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) - } else { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { - // Cache the index of each encountered element - if ( useCache ) { - (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf.call( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - if ( (oldCache = outerCache[ dir ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - outerCache[ dir ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf.call( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context !== document && context; - } - - // Add elements passing elementMatchers directly to results - // Keep `i` a string if there are no elements so `matchedCount` will be "00" below - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // Apply set filters to unmatched elements - matchedCount += i; - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is no seed and only one group - if ( match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - support.getById && context.nodeType === 9 && documentIsHTML && - Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome<14 -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( div1 ) { - // Should return 1, but returns 4 (following) - return div1.compareDocumentPosition( document.createElement("div") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( div ) { - div.innerHTML = ""; - return div.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( div ) { - div.innerHTML = ""; - div.firstChild.setAttribute( "value", "" ); - return div.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( div ) { - return div.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - - -var rneedsContext = jQuery.expr.match.needsContext; - -var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - /* jshint -W018 */ - return !!qualifier.call( elem, i, elem ) !== not; - }); - - } - - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - }); - - } - - if ( typeof qualifier === "string" ) { - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - qualifier = jQuery.filter( qualifier, elements ); - } - - return jQuery.grep( elements, function( elem ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; - }); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 && elem.nodeType === 1 ? - jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : - jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - })); -}; - -jQuery.fn.extend({ - find: function( selector ) { - var i, - ret = [], - self = this, - len = self.length; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }) ); - } - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - // Needed because $( selector, context ) becomes $( context ).find( selector ) - ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); - ret.selector = this.selector ? this.selector + " " + selector : selector; - return ret; - }, - filter: function( selector ) { - return this.pushStack( winnow(this, selector || [], false) ); - }, - not: function( selector ) { - return this.pushStack( winnow(this, selector || [], true) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -}); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, - - init = jQuery.fn.init = function( selector, context ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - - // scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[1], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return typeof rootjQuery.ready !== "undefined" ? - rootjQuery.ready( selector ) : - // Execute immediately if ready is not present - selector( jQuery ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.extend({ - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -jQuery.fn.extend({ - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { - // Always skip document fragments - if ( cur.nodeType < 11 && (pos ? - pos.index(cur) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector(cur, selectors)) ) { - - matched.push( cur ); - break; - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.unique( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - if ( this.length > 1 ) { - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - ret = jQuery.unique( ret ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - } - - return this.pushStack( ret ); - }; -}); -var rnotwhite = (/\S+/g); - - - -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // First callback to fire (used internally by add and fireWith) - firingStart, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - var type = jQuery.type( arg ); - if ( type === "function" ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && type !== "string" ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); - }, - // Remove all callbacks from the list - empty: function() { - list = []; - firingLength = 0; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( list && ( !fired || stack ) ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ](function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); - } - }); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] - deferred[ tuple[0] ] = function() { - deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); - return this; - }; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( values === progressValues ) { - deferred.notifyWith( contexts, values ); - - } else if ( !(--remaining) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); - - -// The deferred used on DOM ready -var readyList; - -jQuery.fn.ready = function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; -}; - -jQuery.extend({ - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); - jQuery( document ).off( "ready" ); - } - } -}); - -/** - * Clean-up method for dom ready events - */ -function detach() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", completed, false ); - window.removeEventListener( "load", completed, false ); - - } else { - document.detachEvent( "onreadystatechange", completed ); - window.detachEvent( "onload", completed ); - } -} - -/** - * The ready event handler and self cleanup method - */ -function completed() { - // readyState === "complete" is good enough for us to call the dom ready in oldIE - if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { - detach(); - jQuery.ready(); - } -} - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the browser event has already occurred. - // we once tried to use readyState "interactive" here, but it caused issues like the one - // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", completed ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", completed ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // detach all dom ready events - detach(); - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - - -var strundefined = typeof undefined; - - - -// Support: IE<9 -// Iteration over object's inherited properties before its own -var i; -for ( i in jQuery( support ) ) { - break; -} -support.ownLast = i !== "0"; - -// Note: most support tests are defined in their respective modules. -// false until the test is run -support.inlineBlockNeedsLayout = false; - -// Execute ASAP in case we need to set body.style.zoom -jQuery(function() { - // Minified: var a,b,c,d - var val, div, body, container; - - body = document.getElementsByTagName( "body" )[ 0 ]; - if ( !body || !body.style ) { - // Return for frameset docs that don't have a body - return; - } - - // Setup - div = document.createElement( "div" ); - container = document.createElement( "div" ); - container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; - body.appendChild( container ).appendChild( div ); - - if ( typeof div.style.zoom !== strundefined ) { - // Support: IE<8 - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; - - support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; - if ( val ) { - // Prevent IE 6 from affecting layout for positioned elements #11048 - // Prevent IE from shrinking the body in IE 7 mode #12869 - // Support: IE<8 - body.style.zoom = 1; - } - } - - body.removeChild( container ); -}); - - - - -(function() { - var div = document.createElement( "div" ); - - // Execute the test only if not already executed in another module. - if (support.deleteExpando == null) { - // Support: IE<9 - support.deleteExpando = true; - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - } - - // Null elements to avoid leaks in IE. - div = null; -})(); - - -/** - * Determines whether an object can have data - */ -jQuery.acceptData = function( elem ) { - var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], - nodeType = +elem.nodeType || 1; - - // Do not set data on non-element DOM nodes because it will not be cleared (#8335). - return nodeType !== 1 && nodeType !== 9 ? - false : - - // Nodes accept data unless otherwise specified; rejection can be conditional - !noData || noData !== true && elem.getAttribute("classid") === noData; -}; - - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /([A-Z])/g; - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} - -function internalData( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var ret, thisCache, - internalKey = jQuery.expando, - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - // Avoid exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( typeof name === "string" ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; -} - -function internalRemoveData( elem, name, pvt ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } else { - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = name.concat( jQuery.map( name, jQuery.camelCase ) ); - } - - i = name.length; - while ( i-- ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - /* jshint eqeqeq: false */ - } else if ( support.deleteExpando || cache != cache.window ) { - /* jshint eqeqeq: true */ - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } -} - -jQuery.extend({ - cache: {}, - - // The following elements (space-suffixed to avoid Object.prototype collisions) - // throw uncatchable exceptions if you attempt to set expando properties - noData: { - "applet ": true, - "embed ": true, - // ...but Flash objects (which have this classid) *can* handle expandos - "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data ) { - return internalData( elem, name, data ); - }, - - removeData: function( elem, name ) { - return internalRemoveData( elem, name ); - }, - - // For internal use only. - _data: function( elem, name, data ) { - return internalData( elem, name, data, true ); - }, - - _removeData: function( elem, name ) { - return internalRemoveData( elem, name, true ); - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var i, name, data, - elem = this[0], - attrs = elem && elem.attributes; - - // Special expections of .data basically thwart jQuery.access, - // so implement the relevant behavior ourselves - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE11+ - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice(5) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - return arguments.length > 1 ? - - // Sets one value - this.each(function() { - jQuery.data( this, key, value ); - }) : - - // Gets one value - // Try to fetch any internally stored data first - elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - - -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery._removeData( elem, type + "queue" ); - jQuery._removeData( elem, key ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = jQuery._data( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHidden = function( elem, el ) { - // isHidden might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); - }; - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - length = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < length; i++ ) { - fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); - } - } - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; -}; -var rcheckableType = (/^(?:checkbox|radio)$/i); - - - -(function() { - // Minified: var a,b,c - var input = document.createElement( "input" ), - div = document.createElement( "div" ), - fragment = document.createDocumentFragment(); - - // Setup - div.innerHTML = "
a"; - - // IE strips leading whitespace when .innerHTML is used - support.leadingWhitespace = div.firstChild.nodeType === 3; - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - support.tbody = !div.getElementsByTagName( "tbody" ).length; - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - support.html5Clone = - document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - input.type = "checkbox"; - input.checked = true; - fragment.appendChild( input ); - support.appendChecked = input.checked; - - // Make sure textarea (and checkbox) defaultValue is properly cloned - // Support: IE6-IE11+ - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // #11217 - WebKit loses check when the name is after the checked attribute - fragment.appendChild( div ); - div.innerHTML = ""; - - // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 - // old WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE<9 - // Opera does not clone events (and typeof div.attachEvent === undefined). - // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() - support.noCloneEvent = true; - if ( div.attachEvent ) { - div.attachEvent( "onclick", function() { - support.noCloneEvent = false; - }); - - div.cloneNode( true ).click(); - } - - // Execute the test only if not already executed in another module. - if (support.deleteExpando == null) { - // Support: IE<9 - support.deleteExpando = true; - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - } -})(); - - -(function() { - var i, eventName, - div = document.createElement( "div" ); - - // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) - for ( i in { submit: true, change: true, focusin: true }) { - eventName = "on" + i; - - if ( !(support[ i + "Bubbles" ] = eventName in window) ) { - // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) - div.setAttribute( eventName, "t" ); - support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; - } - } - - // Null elements to avoid leaks in IE. - div = null; -})(); - - -var rformElems = /^(?:input|select|textarea)$/i, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - var tmp, events, t, handleObjIn, - special, eventHandle, handleObj, - handlers, type, namespaces, origType, - elemData = jQuery._data( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !(events = elemData.events) ) { - events = elemData.events = {}; - } - if ( !(eventHandle = elemData.handle) ) { - eventHandle = elemData.handle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnotwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !(handlers = events[ type ]) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - var j, handleObj, tmp, - origCount, t, events, - special, handlers, type, - namespaces, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnotwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery._removeData( elem, "events" ); - } - }, - - trigger: function( event, data, elem, onlyHandlers ) { - var handle, ontype, cur, - bubbleType, special, tmp, i, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf(":") < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join("."); - event.namespace_re = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === (elem.ownerDocument || document) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && jQuery.acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && - jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - try { - elem[ type ](); - } catch ( e ) { - // IE<9 dies on focus/blur to hidden element (#1486,#12518) - // only reproducible on winXP IE8 native, not IE9 in IE8 mode - } - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); - - var i, ret, handleObj, matched, j, - handlerQueue = [], - args = slice.call( arguments ), - handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( (event.result = ret) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var sel, handleObj, matches, i, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { - - /* jshint eqeqeq: false */ - for ( ; cur != this; cur = cur.parentNode || this ) { - /* jshint eqeqeq: true */ - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) >= 0 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matches[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, handlers: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( delegateCount < handlers.length ) { - handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); - } - - return handlerQueue; - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: IE<9 - // Fix target property (#1925) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Support: Chrome 23+, Safari? - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Support: IE<9 - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) - event.metaKey = !!event.metaKey; - - return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var body, eventDoc, doc, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - special: { - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - try { - this.focus(); - return false; - } catch ( e ) { - // Support: IE<9 - // If we error on focus to hidden element (#1486, #12518), - // let .trigger() run the handlers - } - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return jQuery.nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === strundefined ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - // Support: IE < 9, Android < 4.0 - src.returnValue === false ? - returnTrue : - returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - if ( !e ) { - return; - } - - // If preventDefault exists, run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // Support: IE - // Otherwise set the returnValue property of the original event to false - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - if ( !e ) { - return; - } - // If stopPropagation exists, run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - - // Support: IE - // Set the cancelBubble property of the original event to true - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && e.stopImmediatePropagation ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "submitBubbles" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "submitBubbles", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "changeBubbles", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return !rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = jQuery._data( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = jQuery._data( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - jQuery._removeData( doc, fix ); - } else { - jQuery._data( doc, fix, attaches ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var type, origFn; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - var elem = this[0]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -}); - - -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /\s*$/g, - - // We have to close these tags to support XHTML (#13200) - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
", "
" ], - area: [ 1, "", "" ], - param: [ 1, "", "" ], - thead: [ 1, "", "
" ], - tr: [ 2, "", "
" ], - col: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, - // unless wrapped in a div with non-breaking characters in front of it. - _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -function getAll( context, tag ) { - var elems, elem, - i = 0, - found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : - undefined; - - if ( !found ) { - for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { - if ( !tag || jQuery.nodeName( elem, tag ) ) { - found.push( elem ); - } else { - jQuery.merge( found, getAll( elem, tag ) ); - } - } - } - - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], found ) : - found; -} - -// Used in buildFragment, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -// Support: IE<8 -// Manipulating tables requires a tbody -function manipulationTarget( elem, content ) { - return jQuery.nodeName( elem, "table" ) && - jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? - - elem.getElementsByTagName("tbody")[0] || - elem.appendChild( elem.ownerDocument.createElement("tbody") ) : - elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - if ( match ) { - elem.type = match[1]; - } else { - elem.removeAttribute("type"); - } - return elem; -} - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var elem, - i = 0; - for ( ; (elem = elems[i]) != null; i++ ) { - jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); - } -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function fixCloneNodeIssues( src, dest ) { - var nodeName, e, data; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - nodeName = dest.nodeName.toLowerCase(); - - // IE6-8 copies events bound via attachEvent when using cloneNode. - if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { - data = jQuery._data( dest ); - - for ( e in data.events ) { - jQuery.removeEvent( dest, e, data.handle ); - } - - // Event data gets referenced instead of copied if the expando gets copied too - dest.removeAttribute( jQuery.expando ); - } - - // IE blanks contents when cloning scripts, and tries to evaluate newly-set text - if ( nodeName === "script" && dest.text !== src.text ) { - disableScript( dest ).text = src.text; - restoreScript( dest ); - - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - } else if ( nodeName === "object" ) { - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.defaultSelected = dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var destElements, node, clone, i, srcElements, - inPage = jQuery.contains( elem.ownerDocument, elem ); - - if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!support.noCloneEvent || !support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - // Fix all IE cloning issues - for ( i = 0; (node = srcElements[i]) != null; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - fixCloneNodeIssues( node, destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0; (node = srcElements[i]) != null; i++ ) { - cloneCopyEvent( node, destElements[i] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - destElements = srcElements = node = null; - - // Return the cloned set - return clone; - }, - - buildFragment: function( elems, context, scripts, selection ) { - var j, elem, contains, - tmp, tag, tbody, wrap, - l = elems.length, - - // Ensure a safe fragment - safe = createSafeFragment( context ), - - nodes = [], - i = 0; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || safe.appendChild( context.createElement("div") ); - - // Deserialize a standard representation - tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - - tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; - - // Descend through wrappers to the right content - j = wrap[0]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Manually add leading whitespace removed by IE - if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); - } - - // Remove IE's autoinserted from table fragments - if ( !support.tbody ) { - - // String was a , *may* have spurious - elem = tag === "table" && !rtbody.test( elem ) ? - tmp.firstChild : - - // String was a bare or - wrap[1] === "
" && !rtbody.test( elem ) ? - tmp : - 0; - - j = elem && elem.childNodes.length; - while ( j-- ) { - if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { - elem.removeChild( tbody ); - } - } - } - - jQuery.merge( nodes, tmp.childNodes ); - - // Fix #12392 for WebKit and IE > 9 - tmp.textContent = ""; - - // Fix #12392 for oldIE - while ( tmp.firstChild ) { - tmp.removeChild( tmp.firstChild ); - } - - // Remember the top-level container for proper cleanup - tmp = safe.lastChild; - } - } - } - - // Fix #11356: Clear elements from fragment - if ( tmp ) { - safe.removeChild( tmp ); - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !support.appendChecked ) { - jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); - } - - i = 0; - while ( (elem = nodes[ i++ ]) ) { - - // #4087 - If origin and destination elements are the same, and this is - // that element, do not do anything - if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( safe.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( (elem = tmp[ j++ ]) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - tmp = null; - - return safe; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var elem, type, id, data, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( typeof elem.removeAttribute !== strundefined ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - deletedIds.push( id ); - } - } - } - } - } -}); - -jQuery.fn.extend({ - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - append: function() { - return this.domManip( arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip( arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - }); - }, - - before: function() { - return this.domManip( arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - }); - }, - - after: function() { - return this.domManip( arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - }); - }, - - remove: function( selector, keepData /* Internal Use Only */ ) { - var elem, - elems = selector ? jQuery.filter( selector, this ) : this, - i = 0; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem ) ); - } - - if ( elem.parentNode ) { - if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { - setGlobalEval( getAll( elem, "script" ) ); - } - elem.parentNode.removeChild( elem ); - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - - // If this is a select, ensure that it displays empty (#12336) - // Support: IE<9 - if ( elem.options && jQuery.nodeName( elem, "select" ) ) { - elem.options.length = 0; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map(function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var arg = arguments[ 0 ]; - - // Make the changes, replacing each context element with the new content - this.domManip( arguments, function( elem ) { - arg = this.parentNode; - - jQuery.cleanData( getAll( this ) ); - - if ( arg ) { - arg.replaceChild( elem, this ); - } - }); - - // Force removal if there was no new content (e.g., from empty arguments) - return arg && (arg.length || arg.nodeType) ? this : this.remove(); - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, callback ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var first, node, hasScripts, - scripts, doc, fragment, - i = 0, - l = this.length, - set = this, - iNoClone = l - 1, - value = args[0], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return this.each(function( index ) { - var self = set.eq( index ); - if ( isFunction ) { - args[0] = value.call( this, index, self.html() ); - } - self.domManip( args, callback ); - }); - } - - if ( l ) { - fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( this[i], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - - if ( node.src ) { - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - } - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - } - } - - return this; - } -}); - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone(true); - jQuery( insert[i] )[ original ]( elems ); - - // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -}); - - -var iframe, - elemdisplay = {}; - -/** - * Retrieve the actual display of a element - * @param {String} name nodeName of the element - * @param {Object} doc Document object - */ -// Called only from within defaultDisplay -function actualDisplay( name, doc ) { - var style, - elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), - - // getDefaultComputedStyle might be reliably used only on attached element - display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? - - // Use of this method is a temporary fix (more like optmization) until something better comes along, - // since it was removed from specification and supported only in FF - style.display : jQuery.css( elem[ 0 ], "display" ); - - // We don't have any data stored on the element, - // so use "detach" method as fast way to get rid of the element - elem.detach(); - - return display; -} - -/** - * Try to determine the default display value of an element - * @param {String} nodeName - */ -function defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - - // Use the already-created iframe if possible - iframe = (iframe || jQuery( "