From 071e4a0f5d9edc4d5c963d6c2839380bfdb91cfa Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Jun 2018 15:07:49 -0700 Subject: [PATCH 1/7] ENH: Use newer pcdsdaq api and do plan_defaults in a cleaner way --- hutch_python/daq.py | 30 ------------------------ hutch_python/load_conf.py | 10 ++++---- hutch_python/plan_defaults.py | 43 +++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 39 deletions(-) delete mode 100644 hutch_python/daq.py diff --git a/hutch_python/daq.py b/hutch_python/daq.py deleted file mode 100644 index b04b8666..00000000 --- a/hutch_python/daq.py +++ /dev/null @@ -1,30 +0,0 @@ -import logging - -from pcdsdaq.daq import Daq - -logger = logging.getLogger(__name__) - - -def get_daq_objs(platform, RE): - """ - Create an instance of ``Daq``. - - This makes sure that the ``Daq`` object is set up to connect to a - hutch's daq, and that it is ready to use in scans with ``RE``. - - Parameters - ---------- - platform: ``int`` - The daq platform variable associated with the hutch's daq. - - RE: ``RunEngine`` - The session's ``RE`` object - - Returns - ------- - objs: ``dict`` - A dictionary that contains a single key, ``daq``, and a ready instance - of the ``Daq`` class. - """ - daq = Daq(platform=platform, RE=RE) - return dict(daq=daq) diff --git a/hutch_python/load_conf.py b/hutch_python/load_conf.py index f001b234..d803bd43 100644 --- a/hutch_python/load_conf.py +++ b/hutch_python/load_conf.py @@ -12,12 +12,12 @@ from bluesky.callbacks.best_effort import BestEffortCallback from bluesky.utils import install_kicker from elog import HutchELog +from pcdsdaq.daq import Daq from pcdsdevices.mv_interface import setup_preset_paths from . import plan_defaults from .cache import LoadCache from .constants import VALID_KEYS -from .daq import get_daq_objs from .exp_load import get_exp_objs from .happi import get_happi_objs, get_lightpath from .namespace import class_namespace, tree_namespace @@ -209,13 +209,13 @@ def load_conf(conf, hutch_dir=None): pass # Collect Plans - cache(plans=plan_defaults) - cache(p=plan_defaults) + cache(bp=plan_defaults.plans) + cache(bps=plan_defaults.plan_stubs) + cache(bpp=plan_defaults.preprocessors) # Daq with safe_load('daq'): - daq_objs = get_daq_objs(daq_platform, RE) - cache(**daq_objs) + cache(daq=Daq(RE=RE)) # Happi db and Lightpath if db is not None: diff --git a/hutch_python/plan_defaults.py b/hutch_python/plan_defaults.py index 23e33d27..86b3c074 100644 --- a/hutch_python/plan_defaults.py +++ b/hutch_python/plan_defaults.py @@ -1,4 +1,39 @@ -# flake8: NOQA -from bluesky.plans import * -from pcdsdaq.plans import (calib_cycle, calib_at_step, - daq_wrapper, daq_decorator) +from importlib import import_module +from inspect import isgeneratorfunction +from types import SimpleNamespace + + +def collect_plans(modules): + """ + Take all the plans in ``modules`` and collect them into a namespace. + + Arguments + --------- + modules: ``list of str`` + The modules to extract plans from. + """ + plans = {} + for module_name in modules: + module = import_module(module_name) + for name, obj in module.__dict__.items(): + try: + # Only include things that are natively from this module + if obj.__module__ == module_name: + try: + # Check the __wrapped__ attribute for decorators + if isgeneratorfunction(obj.__wrapped__): + plans[name] = obj + except AttributeError: + # Not a decorator, check obj + if isgeneratorfunction(obj): + plans[name] = obj + except AttributeError: + # obj did not have __module__, probably a builtin + pass + return SimpleNamespace(**plans) + + +plans = collect_plans(['bluesky.plans']) +plan_stubs = collect_plans(['bluesky.plan_stubs']) +preprocessors = collect_plans(['bluesky.preprocessors', + 'pcdsdaq.preprocessors']) From 6c6f240043a33c30c74557f65339f083db1cd6cb Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Jun 2018 15:08:54 -0700 Subject: [PATCH 2/7] BLD: This will need the next pcdsdaq release. --- conda-recipe/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 76acd779..5c3c1279 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -23,7 +23,7 @@ requirements: - pyfiglet - happi >=1.1.1 - pcdsdevices >=0.6.0 - - pcdsdaq >=1.1.0 + - pcdsdaq >1.2.0 - psdm_qs_cli >=0.2.0 - lightpath >=0.3.0 - elog From 2b551e3ffc4827f54241b7ee3297e1e50c91f48e Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Jun 2018 15:37:10 -0700 Subject: [PATCH 3/7] DOC: Add to the release notes --- docs/source/releases.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/source/releases.rst b/docs/source/releases.rst index b75c0e95..11cfe161 100644 --- a/docs/source/releases.rst +++ b/docs/source/releases.rst @@ -4,6 +4,13 @@ Release History Next Release ============ +Features +-------- +- Provide well-curated namespaces for ``bluesky`` plans. These are in the + shell as ``bp`` (bluesky plans) for normal plans, ``bps`` (bluesky plan + stubs) for plans that are not complete on their own, and ``bpp`` + (bluesky plan preprocessors) for plans that modify other plans. + Bugfixes --------- - Show a correct error message when there is an ``ImportError`` in an From 9de5630d3b4b71ee247b1744d6a56c85fd1187d0 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Jun 2018 15:52:02 -0700 Subject: [PATCH 4/7] DOC: Remove reference to removed file --- docs/source/load_parts.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/load_parts.rst b/docs/source/load_parts.rst index 845e01d3..37ec0d81 100644 --- a/docs/source/load_parts.rst +++ b/docs/source/load_parts.rst @@ -7,7 +7,6 @@ Submodules used by :py:mod:`load_conf` :toctree: generated :nosignatures: - hutch_python.daq.get_daq_objs hutch_python.happi.get_happi_objs hutch_python.happi.get_lightpath hutch_python.user_load.get_user_objs From 6dbff44db7e88e1c7319ae6fc781134e1202cb89 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Jun 2018 15:52:29 -0700 Subject: [PATCH 5/7] DOC: Remove reference to platform argument --- docs/source/yaml_files.rst | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/docs/source/yaml_files.rst b/docs/source/yaml_files.rst index ed9948e4..03edfc2a 100644 --- a/docs/source/yaml_files.rst +++ b/docs/source/yaml_files.rst @@ -3,7 +3,7 @@ Yaml Files ``hutch-python`` uses a ``conf.yml`` file for basic configuration. This is a standard yaml file with five valid keys: -``hutch``, ``db``, ``load``, ``experiment``, and ``daq_platform``. +``hutch``, ``db``, ``load``, and ``experiment``. hutch @@ -86,23 +86,6 @@ This key is used to force the questionnaire and experiment file to be from a particular experiment. -daq_platform ------------- - -The ``daq_platform`` is another optional key that can be used to configure -which ``platform`` your running daq uses on a per-hutch or per-host basis. -The default ``platform`` is zero, but you can set a different ``platform`` -for your hutch by using the ``default`` key as shown below. You can set a -platform for a particular host by using that host's name as a key as shown -below. - -.. code-block:: YAML - - daq_platform: - default: 4 - cxi-control: 5 - - Full File Example ----------------- @@ -114,6 +97,3 @@ Full File Example load: - xpp.beamline - - daq_platform: - default: 1 From 2de5cc68ed6e240e3d42888be40b4c08627b2e2b Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 7 Jun 2018 17:23:03 -0700 Subject: [PATCH 6/7] DOC: Fix errors and update tutorial for recent changes --- docs/source/tutorial.ipynb | 109 ++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/docs/source/tutorial.ipynb b/docs/source/tutorial.ipynb index f65d3b53..ba05ae80 100644 --- a/docs/source/tutorial.ipynb +++ b/docs/source/tutorial.ipynb @@ -201,7 +201,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "There are a few utilities if you don't see a grouping you like, `class_namespace`, `metadata_namespace` allow you to create these groupings quickly based on information about a device." + "There are a few utilities if you don't see a grouping you like, `class_namespace`, `tree_namespace` allow you to create these groupings quickly based on information about a device." ] }, { @@ -458,11 +458,18 @@ "metadata": {}, "source": [ "One of the major additions the `hutch_python` restructuring gives us is access to `bluesky` scanning capabilities. A full tutorial is available at http://nsls-ii.github.io/bluesky/tutorial. This very brief introduction assumes you know a little about how `bluesky` works in general. The major keys are:\n", + "\n", "* The `RunEngine` object is responsible for executing all scans. \n", "* Experimental procedures are described in `plans`, python generators which allow sophisticated flow control\n", "\n", "\n", - "The hutch-python environment should already a `RunEngine` instatiated for you to begin playing\n", + "The hutch-python environment should already have a `RunEngine` instatiated for you to begin playing.\n", + "It also has built-in `bluesky` `plans` that are tab-accessible in the following objects:\n", + "\n", + "* `bp`: full plans that are ready to use\n", + "* `bps`: partial plans that can be used as building blocks for larger plans\n", + "* `bpp`: wrappers that add functionality to existing plans\n", + "\n", "\n", "#### Note\n", "In the examples below we run our scans with simulated hardware built-in to the `ophyd` library.\n" @@ -481,7 +488,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The simplest plan in `bluesky` is `count`, a simple reading of a detector. A basic execution looks like this where we take 5 measurements from the detector. Take note what is actually happen here. We create an instance of `count` then we pass this into `RE()`. " + "The simplest plan in `bluesky` is `count`, a simple reading of a detector. A basic execution looks like this where we take 5 measurements from the detector. Take note what is actually happenning here. We create an instance of `count` then we pass this into `RE()`. " ] }, { @@ -498,9 +505,20 @@ "New stream: 'primary'\n", "+-----------+------------+------------+\n", "| seq_num | time | det |\n", - "+-----------+------------+------------+\n" + "+-----------+------------+------------+\n", + "| 1 | 09:18:37.9 | 1.000 |\n", + "| 2 | 09:18:38.1 | 1.000 |\n", + "| 3 | 09:18:38.1 | 1.000 |\n", + "| 4 | 09:18:38.1 | 1.000 |\n", + "| 5 | 09:18:38.1 | 1.000 |\n", + "+-----------+------------+------------+\n", + "generator count ['dda5fba6'] (scan num: 1)\n", + "\n", + "\n", + "\n" ] }, + { "data": { "application/javascript": [ @@ -1293,22 +1311,6 @@ "metadata": {}, "output_type": "display_data" }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "| 1 | 09:18:37.9 | 1.000 |\n", - "| 2 | 09:18:38.1 | 1.000 |\n", - "| 3 | 09:18:38.1 | 1.000 |\n", - "| 4 | 09:18:38.1 | 1.000 |\n", - "| 5 | 09:18:38.1 | 1.000 |\n", - "+-----------+------------+------------+\n", - "generator count ['dda5fba6'] (scan num: 1)\n", - "\n", - "\n", - "\n" - ] - }, { "data": { "text/plain": [ @@ -1321,7 +1323,7 @@ } ], "source": [ - "RE(plans.count([det], num=5))" + "RE(bp.count([det], num=5))" ] }, { @@ -1345,7 +1347,22 @@ "New stream: 'primary'\n", "+-----------+------------+------------+------------+\n", "| seq_num | time | motor | det |\n", - "+-----------+------------+------------+------------+\n" + "+-----------+------------+------------+------------+\n", + "| 1 | 09:18:38.3 | -5.000 | 0.000 |\n", + "| 2 | 09:18:38.4 | -3.889 | 0.001 |\n", + "| 3 | 09:18:38.4 | -2.778 | 0.021 |\n", + "| 4 | 09:18:38.4 | -1.667 | 0.249 |\n", + "| 5 | 09:18:38.4 | -0.556 | 0.857 |\n", + "| 6 | 09:18:38.4 | 0.556 | 0.857 |\n", + "| 7 | 09:18:38.5 | 1.667 | 0.249 |\n", + "| 8 | 09:18:38.5 | 2.778 | 0.021 |\n", + "| 9 | 09:18:38.5 | 3.889 | 0.001 |\n", + "| 10 | 09:18:38.5 | 5.000 | 0.000 |\n", + "+-----------+------------+------------+------------+\n", + "generator scan ['8f13258c'] (scan num: 2)\n", + "\n", + "\n", + "\n" ] }, { @@ -2140,27 +2157,6 @@ "metadata": {}, "output_type": "display_data" }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "| 1 | 09:18:38.3 | -5.000 | 0.000 |\n", - "| 2 | 09:18:38.4 | -3.889 | 0.001 |\n", - "| 3 | 09:18:38.4 | -2.778 | 0.021 |\n", - "| 4 | 09:18:38.4 | -1.667 | 0.249 |\n", - "| 5 | 09:18:38.4 | -0.556 | 0.857 |\n", - "| 6 | 09:18:38.4 | 0.556 | 0.857 |\n", - "| 7 | 09:18:38.5 | 1.667 | 0.249 |\n", - "| 8 | 09:18:38.5 | 2.778 | 0.021 |\n", - "| 9 | 09:18:38.5 | 3.889 | 0.001 |\n", - "| 10 | 09:18:38.5 | 5.000 | 0.000 |\n", - "+-----------+------------+------------+------------+\n", - "generator scan ['8f13258c'] (scan num: 2)\n", - "\n", - "\n", - "\n" - ] - }, { "data": { "text/plain": [ @@ -2173,7 +2169,7 @@ } ], "source": [ - "plan = plans.scan([det], motor, -5, 5, num=10)\n", + "plan = bp.scan([det], motor, -5, 5, num=10)\n", "RE(plan)" ] }, @@ -2281,13 +2277,13 @@ } ], "source": [ - "RE(plans.adaptive_scan([det], 'det', motor,\n", - " start=-15,\n", - " stop=10,\n", - " min_step=0.01,\n", - " max_step=5,\n", - " target_delta=.05,\n", - " backstep=True))" + "RE(bp.adaptive_scan([det], 'det', motor,\n", + " start=-15,\n", + " stop=10,\n", + " min_step=0.01,\n", + " max_step=5,\n", + " target_delta=.05,\n", + " backstep=True))" ] }, { @@ -2296,7 +2292,7 @@ "source": [ "### Including the DAQ\n", "\n", - "What has been ignored in these examples is the inclusion of the DAQ. There are a few simple helper functions that cover basic modes of operations. The simplest behavior is just running the DAQ throughout the whole scan and stopping at the end. This can be accomlished by passing any plan you want to run this way through the `daq_wrapper` and setting the mode to `\"on\"`" + "What has been ignored in these examples is the inclusion of the DAQ. There are a few simple helper functions that cover basic modes of operations. The simplest behavior is just running the DAQ throughout the whole scan and stopping at the end. This can be accomlished by passing any plan you want to run this way through the `daq_wrapper`" ] }, { @@ -2344,14 +2340,14 @@ } ], "source": [ - "RE(plans.daq_wrapper(plans.scan([det], motor, -5, 5, num=10), mode='on'))" + "RE(bpp.daq_wrapper(bp.scan([det], motor, -5, 5, num=10)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "More complex behavior is available. For instance, if you want the DAQ to only run at certain points in your scan you can set the mode to `\"manual\"`. This requries the plan itself to start and stop the DAQ when necessary. The most common mode of operation for this mode is when performing calibration cycles. For this we can utilize the `calib_at_step` stub plan built-in into the `pcdsdaq` module. This function is then placed in the `per_step`" + "More complex behavior is available. You can have the daq run at every scan step by passing it into a scan instead of or in addition to a `det` input from any of the previous examples. The most common mode of operation for this mode is when performing calibration cycles. You can also make the daq run at very specific times by writing your own plans that do `yield from bps.trigger_and_read(daq)`." ] }, { @@ -2399,9 +2395,8 @@ } ], "source": [ - "RE(plans.daq_wrapper(plans.scan([det], motor, -5, 5, num=10,\n", - " per_step=plans.calib_at_step(events=50)),\n", - " mode='manual'))" + "daq.configure(events=120)\n", + "RE(bp.scan([daq, det], motor, -5, 5, num=10))" ] } ], From 2496fd5771644461f4b389e0c2baa94bb6ae79fe Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 27 Jun 2018 16:44:35 -0700 Subject: [PATCH 7/7] TST: remove outdated test --- hutch_python/tests/test_load_conf.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/hutch_python/tests/test_load_conf.py b/hutch_python/tests/test_load_conf.py index 7225f392..8b5e0f9c 100644 --- a/hutch_python/tests/test_load_conf.py +++ b/hutch_python/tests/test_load_conf.py @@ -38,25 +38,6 @@ def test_conf_empty(): assert len(objs) > 1 -def test_conf_platform(): - logger.debug('test_conf_platform') - set_sim_mode(True) - # No platform - objs = load_conf({}) - assert objs['daq']._plat == 0 - # Define default platform - objs = load_conf({'daq_platform': {'default': 1}}) - assert objs['daq']._plat == 1 - # Define host platform - hostname = gethostname() - objs = load_conf({'daq_platform': {hostname: 2}}) - assert objs['daq']._plat == 2 - # Define both - objs = load_conf({'daq_platform': {'default': 3, - hostname: 4}}) - assert objs['daq']._plat == 4 - - def test_elog(monkeypatch, temporary_config): monkeypatch.setattr(hutch_python.load_conf, 'HutchELog', ELog) # No platform