From 53801cd02ec879eb66ac0dc5746727a8744fb1d3 Mon Sep 17 00:00:00 2001 From: Callum Forrester Date: Thu, 16 Jan 2025 08:19:46 +0000 Subject: [PATCH 1/5] Working system test for count plan --- src/blueapi/startup/example_devices.py | 16 ++++++++++ tests/system_tests/test_blueapi_system.py | 38 ++++++++++++++++++++--- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/blueapi/startup/example_devices.py b/src/blueapi/startup/example_devices.py index a472137dd..65907c4b0 100644 --- a/src/blueapi/startup/example_devices.py +++ b/src/blueapi/startup/example_devices.py @@ -1,7 +1,23 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + +from dodal.common.beamlines.beamline_utils import set_path_provider +from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitPathProvider from ophyd.sim import Syn2DGauss, SynGauss, SynSignal from .simmotor import BrokenSynAxis, SynAxisWithMotionEvents +# Some of our plans such as "count" and "spec_scan" require this global +# singleton to be set +_tmp_dir = Path(TemporaryDirectory().name) +set_path_provider( + StaticVisitPathProvider( + "t01", + _tmp_dir, + client=LocalDirectoryServiceClient(), + ) +) + def x(name="x") -> SynAxisWithMotionEvents: return SynAxisWithMotionEvents(name=name, delay=1.0, events_per_move=8) diff --git a/tests/system_tests/test_blueapi_system.py b/tests/system_tests/test_blueapi_system.py index 9505381b1..08f7840e8 100644 --- a/tests/system_tests/test_blueapi_system.py +++ b/tests/system_tests/test_blueapi_system.py @@ -1,4 +1,5 @@ import inspect +import textwrap import time from pathlib import Path @@ -337,11 +338,38 @@ def test_get_current_state_of_environment(client: BlueapiClient): assert client.get_environment().initialized +@pytest.mark.skip( + reason=textwrap.dedent(""" +The client should block until environment reload is complete but it does not, +this interferes with subsequent tests. See +https://github.com/DiamondLightSource/blueapi/issues/742 +""") +) def test_delete_current_environment(client: BlueapiClient): - current_env = client.get_environment() + old_env = client.get_environment() client.reload_environment() new_env = client.get_environment() - assert ( - new_env.initialized is True - and new_env.environment_id != current_env.environment_id - ) + assert new_env.initialized + assert new_env.environment_id != old_env.environment_id + assert new_env.error_message is None + + +@pytest.mark.parametrize( + "task", + [ + Task( + name="count", + params={ + "detectors": [ + "image_det", + "current_det", + ], + "num": 5, + }, + ) + ], +) +def test_plan_runs(client_with_stomp: BlueapiClient, task: Task): + final_event = client_with_stomp.run_task(task) + assert final_event.is_complete() and not final_event.is_error() + assert final_event.state is WorkerState.IDLE From 07ac0142c991e055facb60a3195135a75a950a6e Mon Sep 17 00:00:00 2001 From: Callum Forrester Date: Thu, 16 Jan 2025 08:23:35 +0000 Subject: [PATCH 2/5] Failing system test for spec_scan --- tests/system_tests/test_blueapi_system.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/system_tests/test_blueapi_system.py b/tests/system_tests/test_blueapi_system.py index 08f7840e8..f3e02098b 100644 --- a/tests/system_tests/test_blueapi_system.py +++ b/tests/system_tests/test_blueapi_system.py @@ -7,6 +7,7 @@ from bluesky_stomp.models import BasicAuthentication from pydantic import TypeAdapter from requests.exceptions import ConnectionError +from scanspec.specs import Line from blueapi.client.client import ( BlueapiClient, @@ -366,7 +367,17 @@ def test_delete_current_environment(client: BlueapiClient): ], "num": 5, }, - ) + ), + Task( + name="spec_scan", + params={ + "detectors": [ + "image_det", + "current_det", + ], + "spec": Line("x", 0.0, 10.0, 10) * Line("y", 5.0, 15.0, 20), + }, + ), ], ) def test_plan_runs(client_with_stomp: BlueapiClient, task: Task): From e743c79b3e1370fcbbee5c7bb9f93e7ba6e6edbe Mon Sep 17 00:00:00 2001 From: Callum Forrester Date: Mon, 3 Feb 2025 14:13:07 +0000 Subject: [PATCH 3/5] Remove tmpdir --- src/blueapi/startup/example_devices.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/blueapi/startup/example_devices.py b/src/blueapi/startup/example_devices.py index 65907c4b0..97c2df026 100644 --- a/src/blueapi/startup/example_devices.py +++ b/src/blueapi/startup/example_devices.py @@ -1,5 +1,4 @@ from pathlib import Path -from tempfile import TemporaryDirectory from dodal.common.beamlines.beamline_utils import set_path_provider from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitPathProvider @@ -9,7 +8,9 @@ # Some of our plans such as "count" and "spec_scan" require this global # singleton to be set -_tmp_dir = Path(TemporaryDirectory().name) + +# Workaround for https://github.com/DiamondLightSource/blueapi/issues/784 +_tmp_dir = Path("/does/not/exist") set_path_provider( StaticVisitPathProvider( "t01", From d74e43569a3acfb6d490757c6caa706fc10efd9b Mon Sep 17 00:00:00 2001 From: Callum Forrester Date: Mon, 3 Feb 2025 14:44:06 +0000 Subject: [PATCH 4/5] Fix or xfail system tests --- tests/system_tests/plans.json | 2201 +++++++++++---------- tests/system_tests/test_blueapi_system.py | 26 +- 2 files changed, 1123 insertions(+), 1104 deletions(-) diff --git a/tests/system_tests/plans.json b/tests/system_tests/plans.json index 5fe8259dc..dc4f9865c 100644 --- a/tests/system_tests/plans.json +++ b/tests/system_tests/plans.json @@ -1,1108 +1,1121 @@ { - "plans": [ - { - "name": "move", - "description": "\n Move a device, wrapper for `bp.mv`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target positions\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "moves": { - "title": "Moves", - "type": "object" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - } - }, - "required": [ - "moves" - ], - "title": "move", - "type": "object" - } - }, - { - "name": "count", - "description": "Reads from a number of devices.\n Wraps bluesky.plans.count(det, num, delay, md=metadata) exposing only serializable\n parameters and metadata.", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "detectors": { - "items": { - "type": "bluesky.protocols.Readable" - }, - "title": "Detectors", - "type": "array", - "uniqueItems": true - }, - "num": { - "title": "Num", - "type": "integer" - }, - "delay": { - "anyOf": [ - { - "type": "number" - }, - { - "items": { - "type": "number" - }, - "type": "array" - } - ], - "title": "Delay" - }, - "metadata": { - "anyOf": [ - { - "type": "object" - }, - { - "type": "null" - } - ], - "title": "Metadata" - } - }, - "required": [ - "detectors" - ], - "title": "count", - "type": "object" - } + "plans": [ + { + "name": "stp_snapshot", + "description": "\n Moves devices for pressure and temperature (defaults fetched from the context)\n and captures a single frame from a collection of devices\n\n Args:\n detectors (List[Readable]): A list of devices to read while the sample is at STP\n temperature (Optional[Movable]): A device controlling temperature of the sample,\n defaults to fetching a device name \"sample_temperature\" from the context\n pressure (Optional[Movable]): A device controlling pressure on the sample,\n defaults to fetching a device name \"sample_pressure\" from the context\n Returns:\n MsgGenerator: Plan\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "schema": { + "additionalProperties": false, + "properties": { + "detectors": { + "items": { + "type": "bluesky.protocols.Readable" + }, + "title": "Detectors", + "type": "array" + }, + "temperature": { + "title": "Temperature", + "type": "bluesky.protocols.Movable" + }, + "pressure": { + "title": "Pressure", + "type": "bluesky.protocols.Movable" + } }, - { - "name": "stp_snapshot", - "description": "\n Moves devices for pressure and temperature (defaults fetched from the context)\n and captures a single frame from a collection of devices\n\n Args:\n detectors (List[Readable]): A list of devices to read while the sample is at STP\n temperature (Optional[Movable]): A device controlling temperature of the sample,\n defaults to fetching a device name \"sample_temperature\" from the context\n pressure (Optional[Movable]): A device controlling pressure on the sample,\n defaults to fetching a device name \"sample_pressure\" from the context\n Returns:\n MsgGenerator: Plan\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "detectors": { - "items": { - "type": "bluesky.protocols.Readable" - }, - "title": "Detectors", - "type": "array" - }, - "temperature": { - "title": "Temperature", - "type": "bluesky.protocols.Movable" - }, - "pressure": { - "title": "Pressure", - "type": "bluesky.protocols.Movable" - } + "required": [ + "detectors" + ], + "title": "stp_snapshot", + "type": "object" + } + }, + { + "name": "count", + "description": "Reads from a number of devices.\n Wraps bluesky.plans.count(det, num, delay, md=metadata) exposing only serializable\n parameters and metadata.", + "schema": { + "additionalProperties": false, + "properties": { + "detectors": { + "items": { + "type": "bluesky.protocols.Readable" + }, + "title": "Detectors", + "type": "array", + "uniqueItems": true + }, + "num": { + "title": "Num", + "type": "integer" + }, + "delay": { + "anyOf": [ + { + "type": "number" + }, + { + "items": { + "type": "number" }, - "required": [ - "detectors" - ], - "title": "stp_snapshot", + "type": "array" + } + ], + "title": "Delay" + }, + "metadata": { + "anyOf": [ + { "type": "object" - } + }, + { + "type": "null" + } + ], + "title": "Metadata" + } }, - { - "name": "spec_scan", - "description": "Generic plan for reading `detectors` at every point of a ScanSpec `Spec`.\n A `Spec` is an N-dimensional path.\n ", - "parameter_schema": { - "$defs": { - "Circle": { - "additionalProperties": false, - "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis" - }, - "x_middle": { - "description": "The central x point of the circle", - "title": "X Middle", - "type": "number" - }, - "y_middle": { - "description": "The central y point of the circle", - "title": "Y Middle", - "type": "number" - }, - "radius": { - "description": "Radius of the circle", - "exclusiveMinimum": 0.0, - "title": "Radius", - "type": "number" - }, - "type": { - "const": "Circle", - "default": "Circle", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_middle", - "y_middle", - "radius" - ], - "title": "Circle", - "type": "object" - }, - "CombinationOf": { - "additionalProperties": false, - "description": "Abstract baseclass for a combination of two regions, left and right.", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "CombinationOf", - "default": "CombinationOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "CombinationOf", - "type": "object" - }, - "Concat": { - "additionalProperties": false, - "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))", - "properties": { - "left": { - "$ref": "#/$defs/Spec", - "description": "The left-hand Spec to Concat, midpoints will appear earlier" - }, - "right": { - "$ref": "#/$defs/Spec", - "description": "The right-hand Spec to Concat, midpoints will appear later" - }, - "gap": { - "default": false, - "description": "If True, force a gap in the output at the join", - "title": "Gap", - "type": "boolean" - }, - "check_path_changes": { - "default": true, - "description": "If True path through scan will not be modified by squash", - "title": "Check Path Changes", - "type": "boolean" - }, - "type": { - "const": "Concat", - "default": "Concat", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "Concat", - "type": "object" - }, - "DifferenceOf": { - "additionalProperties": false, - "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, False, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "DifferenceOf", - "default": "DifferenceOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "DifferenceOf", - "type": "object" - }, - "Ellipse": { - "additionalProperties": false, - "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Ellipse\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis" - }, - "x_middle": { - "description": "The central x point of the ellipse", - "title": "X Middle", - "type": "number" - }, - "y_middle": { - "description": "The central y point of the ellipse", - "title": "Y Middle", - "type": "number" - }, - "x_radius": { - "description": "The radius along the x axis of the ellipse", - "exclusiveMinimum": 0.0, - "title": "X Radius", - "type": "number" - }, - "y_radius": { - "description": "The radius along the y axis of the ellipse", - "exclusiveMinimum": 0.0, - "title": "Y Radius", - "type": "number" - }, - "angle": { - "default": 0.0, - "description": "The angle of the ellipse (degrees)", - "title": "Angle", - "type": "number" - }, - "type": { - "const": "Ellipse", - "default": "Ellipse", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_middle", - "y_middle", - "x_radius", - "y_radius" - ], - "title": "Ellipse", - "type": "object" - }, - "IntersectionOf": { - "additionalProperties": false, - "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False, True, False, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "IntersectionOf", - "default": "IntersectionOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "IntersectionOf", - "type": "object" - }, - "Line": { - "additionalProperties": false, - "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 2, 5)", - "properties": { - "axis": { - "description": "An identifier for what to move", - "title": "Axis" - }, - "start": { - "description": "Midpoint of the first point of the line", - "title": "Start", - "type": "number" - }, - "stop": { - "description": "Midpoint of the last point of the line", - "title": "Stop", - "type": "number" - }, - "num": { - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "type": { - "const": "Line", - "default": "Line", - "title": "Type", - "type": "string" - } - }, - "required": [ - "axis", - "start", - "stop", - "num" - ], - "title": "Line", - "type": "object" - }, - "Mask": { - "additionalProperties": false, - "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`", - "properties": { - "spec": { - "$ref": "#/$defs/Spec", - "description": "The Spec containing the source midpoints" - }, - "region": { - "$ref": "#/$defs/Region", - "description": "The Region that midpoints will be inside" - }, - "check_path_changes": { - "default": true, - "description": "If True path through scan will not be modified by squash", - "title": "Check Path Changes", - "type": "boolean" - }, - "type": { - "const": "Mask", - "default": "Mask", - "title": "Type", - "type": "string" - } - }, - "required": [ - "spec", - "region" - ], - "title": "Mask", - "type": "object" - }, - "Polygon": { - "additionalProperties": false, - "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n from scanspec.regions import Polygon\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis" - }, - "x_verts": { - "description": "The Nx1 x coordinates of the polygons vertices", - "items": { - "type": "number" - }, - "minItems": 3, - "title": "X Verts", - "type": "array" - }, - "y_verts": { - "description": "The Nx1 y coordinates of the polygons vertices", - "items": { - "type": "number" - }, - "minItems": 3, - "title": "Y Verts", - "type": "array" - }, - "type": { - "const": "Polygon", - "default": "Polygon", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_verts", - "y_verts" - ], - "title": "Polygon", - "type": "object" - }, - "Product": { - "additionalProperties": false, - "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)", - "properties": { - "outer": { - "$ref": "#/$defs/Spec", - "description": "Will be executed once" - }, - "inner": { - "$ref": "#/$defs/Spec", - "description": "Will be executed len(outer) times" - }, - "type": { - "const": "Product", - "default": "Product", - "title": "Type", - "type": "string" - } - }, - "required": [ - "outer", - "inner" - ], - "title": "Product", - "type": "object" - }, - "Range": { - "additionalProperties": false, - "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, False, False])", - "properties": { - "axis": { - "description": "The name matching the axis to mask in spec", - "title": "Axis" - }, - "min": { - "description": "The minimum inclusive value in the region", - "title": "Min", - "type": "number" - }, - "max": { - "description": "The minimum inclusive value in the region", - "title": "Max", - "type": "number" - }, - "type": { - "const": "Range", - "default": "Range", - "title": "Type", - "type": "string" - } - }, - "required": [ - "axis", - "min", - "max" - ], - "title": "Range", - "type": "object" - }, - "Rectangle": { - "additionalProperties": false, - "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n from scanspec.regions import Rectangle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis" - }, - "x_min": { - "description": "Minimum inclusive x value in the region", - "title": "X Min", - "type": "number" - }, - "y_min": { - "description": "Minimum inclusive y value in the region", - "title": "Y Min", - "type": "number" - }, - "x_max": { - "description": "Maximum inclusive x value in the region", - "title": "X Max", - "type": "number" - }, - "y_max": { - "description": "Maximum inclusive y value in the region", - "title": "Y Max", - "type": "number" - }, - "angle": { - "default": 0.0, - "description": "Clockwise rotation angle of the rectangle", - "title": "Angle", - "type": "number" - }, - "type": { - "const": "Rectangle", - "default": "Rectangle", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_min", - "y_min", - "x_max", - "y_max" - ], - "title": "Rectangle", - "type": "object" - }, - "Region": { - "discriminator": { - "mapping": { - "Circle": "#/$defs/Circle", - "CombinationOf": "#/$defs/CombinationOf", - "DifferenceOf": "#/$defs/DifferenceOf", - "Ellipse": "#/$defs/Ellipse", - "IntersectionOf": "#/$defs/IntersectionOf", - "Polygon": "#/$defs/Polygon", - "Range": "#/$defs/Range", - "Rectangle": "#/$defs/Rectangle", - "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf", - "UnionOf": "#/$defs/UnionOf" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/CombinationOf" - }, - { - "$ref": "#/$defs/UnionOf" - }, - { - "$ref": "#/$defs/IntersectionOf" - }, - { - "$ref": "#/$defs/DifferenceOf" - }, - { - "$ref": "#/$defs/SymmetricDifferenceOf" - }, - { - "$ref": "#/$defs/Range" - }, - { - "$ref": "#/$defs/Rectangle" - }, - { - "$ref": "#/$defs/Polygon" - }, - { - "$ref": "#/$defs/Circle" - }, - { - "$ref": "#/$defs/Ellipse" - } - ] - }, - "Repeat": { - "additionalProperties": false, - "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n from scanspec.specs import Line, Repeat\n\n spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4", - "properties": { - "num": { - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "gap": { - "default": true, - "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap", - "title": "Gap", - "type": "boolean" - }, - "type": { - "const": "Repeat", - "default": "Repeat", - "title": "Type", - "type": "string" - } - }, - "required": [ - "num" - ], - "title": "Repeat", - "type": "object" - }, - "Snake": { - "additionalProperties": false, - "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)", - "properties": { - "spec": { - "$ref": "#/$defs/Spec", - "description": "The Spec to run in reverse every other iteration" - }, - "type": { - "const": "Snake", - "default": "Snake", - "title": "Type", - "type": "string" - } - }, - "required": [ - "spec" - ], - "title": "Snake", - "type": "object" - }, - "Spec": { - "discriminator": { - "mapping": { - "Concat": "#/$defs/Concat", - "Line": "#/$defs/Line", - "Mask": "#/$defs/Mask", - "Product": "#/$defs/Product", - "Repeat": "#/$defs/Repeat", - "Snake": "#/$defs/Snake", - "Spiral": "#/$defs/Spiral", - "Squash": "#/$defs/Squash", - "Static": "#/$defs/Static", - "Zip": "#/$defs/Zip" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/Product" - }, - { - "$ref": "#/$defs/Repeat" - }, - { - "$ref": "#/$defs/Zip" - }, - { - "$ref": "#/$defs/Mask" - }, - { - "$ref": "#/$defs/Snake" - }, - { - "$ref": "#/$defs/Concat" - }, - { - "$ref": "#/$defs/Squash" - }, - { - "$ref": "#/$defs/Line" - }, - { - "$ref": "#/$defs/Static" - }, - { - "$ref": "#/$defs/Spiral" - } - ] - }, - "Spiral": { - "additionalProperties": false, - "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n from scanspec.specs import Spiral\n\n spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)", - "properties": { - "x_axis": { - "description": "An identifier for what to move for x", - "title": "X Axis" - }, - "y_axis": { - "description": "An identifier for what to move for y", - "title": "Y Axis" - }, - "x_start": { - "description": "x centre of the spiral", - "title": "X Start", - "type": "number" - }, - "y_start": { - "description": "y centre of the spiral", - "title": "Y Start", - "type": "number" - }, - "x_range": { - "description": "x width of the spiral", - "title": "X Range", - "type": "number" - }, - "y_range": { - "description": "y width of the spiral", - "title": "Y Range", - "type": "number" - }, - "num": { - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "rotate": { - "default": 0.0, - "description": "How much to rotate the angle of the spiral", - "title": "Rotate", - "type": "number" - }, - "type": { - "const": "Spiral", - "default": "Spiral", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_start", - "y_start", - "x_range", - "y_range", - "num" - ], - "title": "Spiral", - "type": "object" - }, - "Squash": { - "additionalProperties": false, - "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n `why-squash-can-change-path`\n\n.. example_spec::\n\n from scanspec.specs import Line, Squash\n\n spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))", - "properties": { - "spec": { - "$ref": "#/$defs/Spec", - "description": "The Spec to squash the dimensions of" - }, - "check_path_changes": { - "default": true, - "description": "If True path through scan will not be modified by squash", - "title": "Check Path Changes", - "type": "boolean" - }, - "type": { - "const": "Squash", - "default": "Squash", - "title": "Type", - "type": "string" - } - }, - "required": [ - "spec" - ], - "title": "Squash", - "type": "object" - }, - "Static": { - "additionalProperties": false, - "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n from scanspec.specs import Line, Static\n\n spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))", - "properties": { - "axis": { - "description": "An identifier for what to move", - "title": "Axis" - }, - "value": { - "description": "The value at each point", - "title": "Value", - "type": "number" - }, - "num": { - "default": 1, - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "type": { - "const": "Static", - "default": "Static", - "title": "Type", - "type": "string" - } - }, - "required": [ - "axis", - "value" - ], - "title": "Static", - "type": "object" - }, - "SymmetricDifferenceOf": { - "additionalProperties": false, - "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, True, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "SymmetricDifferenceOf", - "default": "SymmetricDifferenceOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "SymmetricDifferenceOf", - "type": "object" - }, - "UnionOf": { - "additionalProperties": false, - "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, True, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "UnionOf", - "default": "UnionOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "UnionOf", - "type": "object" - }, - "Zip": { - "additionalProperties": false, - "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))", - "properties": { - "left": { - "$ref": "#/$defs/Spec", - "description": "The left-hand Spec to Zip, will appear earlier in axes" - }, - "right": { - "$ref": "#/$defs/Spec", - "description": "The right-hand Spec to Zip, will appear later in axes" - }, - "type": { - "const": "Zip", - "default": "Zip", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "Zip", - "type": "object" - } + "required": [ + "detectors" + ], + "title": "count", + "type": "object" + } + }, + { + "name": "spec_scan", + "description": "Generic plan for reading `detectors` at every point of a ScanSpec `Spec`.\n A `Spec` is an N-dimensional path.\n ", + "schema": { + "$defs": { + "Circle_Reference_": { + "additionalProperties": false, + "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis", + "type": "bluesky.protocols.Movable" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis", + "type": "bluesky.protocols.Movable" + }, + "x_middle": { + "description": "The central x point of the circle", + "title": "X Middle", + "type": "number" + }, + "y_middle": { + "description": "The central y point of the circle", + "title": "Y Middle", + "type": "number" + }, + "radius": { + "description": "Radius of the circle", + "exclusiveMinimum": 0, + "title": "Radius", + "type": "number" + }, + "type": { + "const": "Circle", + "default": "Circle", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_middle", + "y_middle", + "radius" + ], + "title": "Circle", + "type": "object" + }, + "CombinationOf_Reference_": { + "additionalProperties": false, + "description": "Abstract baseclass for a combination of two regions, left and right.", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "CombinationOf", + "default": "CombinationOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "CombinationOf", + "type": "object" + }, + "Concat_Reference_": { + "additionalProperties": false, + "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))", + "properties": { + "left": { + "$ref": "#/$defs/Spec", + "description": "The left-hand Spec to Concat, midpoints will appear earlier" + }, + "right": { + "$ref": "#/$defs/Spec", + "description": "The right-hand Spec to Concat, midpoints will appear later" + }, + "gap": { + "default": false, + "description": "If True, force a gap in the output at the join", + "title": "Gap", + "type": "boolean" + }, + "check_path_changes": { + "default": true, + "description": "If True path through scan will not be modified by squash", + "title": "Check Path Changes", + "type": "boolean" + }, + "type": { + "const": "Concat", + "default": "Concat", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "Concat", + "type": "object" + }, + "DifferenceOf_Reference_": { + "additionalProperties": false, + "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, False, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "DifferenceOf", + "default": "DifferenceOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "DifferenceOf", + "type": "object" + }, + "Ellipse_Reference_": { + "additionalProperties": false, + "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Ellipse\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis", + "type": "bluesky.protocols.Movable" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis", + "type": "bluesky.protocols.Movable" + }, + "x_middle": { + "description": "The central x point of the ellipse", + "title": "X Middle", + "type": "number" + }, + "y_middle": { + "description": "The central y point of the ellipse", + "title": "Y Middle", + "type": "number" + }, + "x_radius": { + "description": "The radius along the x axis of the ellipse", + "exclusiveMinimum": 0, + "title": "X Radius", + "type": "number" + }, + "y_radius": { + "description": "The radius along the y axis of the ellipse", + "exclusiveMinimum": 0, + "title": "Y Radius", + "type": "number" + }, + "angle": { + "default": 0, + "description": "The angle of the ellipse (degrees)", + "title": "Angle", + "type": "number" + }, + "type": { + "const": "Ellipse", + "default": "Ellipse", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_middle", + "y_middle", + "x_radius", + "y_radius" + ], + "title": "Ellipse", + "type": "object" + }, + "IntersectionOf_Reference_": { + "additionalProperties": false, + "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False, True, False, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "IntersectionOf", + "default": "IntersectionOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "IntersectionOf", + "type": "object" + }, + "Line_Reference_": { + "additionalProperties": false, + "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 2, 5)", + "properties": { + "axis": { + "description": "An identifier for what to move", + "title": "Axis", + "type": "bluesky.protocols.Movable" + }, + "start": { + "description": "Midpoint of the first point of the line", + "title": "Start", + "type": "number" + }, + "stop": { + "description": "Midpoint of the last point of the line", + "title": "Stop", + "type": "number" + }, + "num": { + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "type": { + "const": "Line", + "default": "Line", + "title": "Type", + "type": "string" + } + }, + "required": [ + "axis", + "start", + "stop", + "num" + ], + "title": "Line", + "type": "object" + }, + "Mask_Reference_": { + "additionalProperties": false, + "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`", + "properties": { + "spec": { + "$ref": "#/$defs/Spec", + "description": "The Spec containing the source midpoints" + }, + "region": { + "$ref": "#/$defs/Region", + "description": "The Region that midpoints will be inside" + }, + "check_path_changes": { + "default": true, + "description": "If True path through scan will not be modified by squash", + "title": "Check Path Changes", + "type": "boolean" + }, + "type": { + "const": "Mask", + "default": "Mask", + "title": "Type", + "type": "string" + } + }, + "required": [ + "spec", + "region" + ], + "title": "Mask", + "type": "object" + }, + "Polygon_Reference_": { + "additionalProperties": false, + "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n from scanspec.regions import Polygon\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis", + "type": "bluesky.protocols.Movable" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis", + "type": "bluesky.protocols.Movable" + }, + "x_verts": { + "description": "The Nx1 x coordinates of the polygons vertices", + "items": { + "type": "number" }, - "additionalProperties": false, - "properties": { - "detectors": { - "items": { - "type": "bluesky.protocols.Readable" - }, - "title": "Detectors", - "type": "array", - "uniqueItems": true - }, - "spec": { - "$ref": "#/$defs/Spec" - }, - "metadata": { - "anyOf": [ - { - "type": "object" - }, - { - "type": "null" - } - ], - "title": "Metadata" - } + "minItems": 3, + "title": "X Verts", + "type": "array" + }, + "y_verts": { + "description": "The Nx1 y coordinates of the polygons vertices", + "items": { + "type": "number" }, - "required": [ - "detectors", - "spec" - ], - "title": "spec_scan", - "type": "object" - } + "minItems": 3, + "title": "Y Verts", + "type": "array" + }, + "type": { + "const": "Polygon", + "default": "Polygon", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_verts", + "y_verts" + ], + "title": "Polygon", + "type": "object" + }, + "Product_Reference_": { + "additionalProperties": false, + "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)", + "properties": { + "outer": { + "$ref": "#/$defs/Spec", + "description": "Will be executed once" + }, + "inner": { + "$ref": "#/$defs/Spec", + "description": "Will be executed len(outer) times" + }, + "type": { + "const": "Product", + "default": "Product", + "title": "Type", + "type": "string" + } + }, + "required": [ + "outer", + "inner" + ], + "title": "Product", + "type": "object" + }, + "Range_Reference_": { + "additionalProperties": false, + "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, False, False])", + "properties": { + "axis": { + "description": "The name matching the axis to mask in spec", + "title": "Axis", + "type": "bluesky.protocols.Movable" + }, + "min": { + "description": "The minimum inclusive value in the region", + "title": "Min", + "type": "number" + }, + "max": { + "description": "The minimum inclusive value in the region", + "title": "Max", + "type": "number" + }, + "type": { + "const": "Range", + "default": "Range", + "title": "Type", + "type": "string" + } + }, + "required": [ + "axis", + "min", + "max" + ], + "title": "Range", + "type": "object" + }, + "Rectangle_Reference_": { + "additionalProperties": false, + "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n from scanspec.regions import Rectangle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis", + "type": "bluesky.protocols.Movable" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis", + "type": "bluesky.protocols.Movable" + }, + "x_min": { + "description": "Minimum inclusive x value in the region", + "title": "X Min", + "type": "number" + }, + "y_min": { + "description": "Minimum inclusive y value in the region", + "title": "Y Min", + "type": "number" + }, + "x_max": { + "description": "Maximum inclusive x value in the region", + "title": "X Max", + "type": "number" + }, + "y_max": { + "description": "Maximum inclusive y value in the region", + "title": "Y Max", + "type": "number" + }, + "angle": { + "default": 0, + "description": "Clockwise rotation angle of the rectangle", + "title": "Angle", + "type": "number" + }, + "type": { + "const": "Rectangle", + "default": "Rectangle", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_min", + "y_min", + "x_max", + "y_max" + ], + "title": "Rectangle", + "type": "object" + }, + "Region": { + "discriminator": { + "mapping": { + "Circle": "#/$defs/Circle_Reference_", + "CombinationOf": "#/$defs/CombinationOf_Reference_", + "DifferenceOf": "#/$defs/DifferenceOf_Reference_", + "Ellipse": "#/$defs/Ellipse_Reference_", + "IntersectionOf": "#/$defs/IntersectionOf_Reference_", + "Polygon": "#/$defs/Polygon_Reference_", + "Range": "#/$defs/Range_Reference_", + "Rectangle": "#/$defs/Rectangle_Reference_", + "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf_Reference_", + "UnionOf": "#/$defs/UnionOf_Reference_" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/CombinationOf_Reference_" + }, + { + "$ref": "#/$defs/UnionOf_Reference_" + }, + { + "$ref": "#/$defs/IntersectionOf_Reference_" + }, + { + "$ref": "#/$defs/DifferenceOf_Reference_" + }, + { + "$ref": "#/$defs/SymmetricDifferenceOf_Reference_" + }, + { + "$ref": "#/$defs/Range_Reference_" + }, + { + "$ref": "#/$defs/Rectangle_Reference_" + }, + { + "$ref": "#/$defs/Polygon_Reference_" + }, + { + "$ref": "#/$defs/Circle_Reference_" + }, + { + "$ref": "#/$defs/Ellipse_Reference_" + } + ] + }, + "Repeat_Reference_": { + "additionalProperties": false, + "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n from scanspec.specs import Line, Repeat\n\n spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4", + "properties": { + "num": { + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "gap": { + "default": true, + "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap", + "title": "Gap", + "type": "boolean" + }, + "type": { + "const": "Repeat", + "default": "Repeat", + "title": "Type", + "type": "string" + } + }, + "required": [ + "num" + ], + "title": "Repeat", + "type": "object" + }, + "Snake_Reference_": { + "additionalProperties": false, + "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)", + "properties": { + "spec": { + "$ref": "#/$defs/Spec", + "description": "The Spec to run in reverse every other iteration" + }, + "type": { + "const": "Snake", + "default": "Snake", + "title": "Type", + "type": "string" + } + }, + "required": [ + "spec" + ], + "title": "Snake", + "type": "object" + }, + "Spec": { + "discriminator": { + "mapping": { + "Concat": "#/$defs/Concat_Reference_", + "Line": "#/$defs/Line_Reference_", + "Mask": "#/$defs/Mask_Reference_", + "Product": "#/$defs/Product_Reference_", + "Repeat": "#/$defs/Repeat_Reference_", + "Snake": "#/$defs/Snake_Reference_", + "Spiral": "#/$defs/Spiral_Reference_", + "Squash": "#/$defs/Squash_Reference_", + "Static": "#/$defs/Static_Reference_", + "Zip": "#/$defs/Zip_Reference_" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/Product_Reference_" + }, + { + "$ref": "#/$defs/Repeat_Reference_" + }, + { + "$ref": "#/$defs/Zip_Reference_" + }, + { + "$ref": "#/$defs/Mask_Reference_" + }, + { + "$ref": "#/$defs/Snake_Reference_" + }, + { + "$ref": "#/$defs/Concat_Reference_" + }, + { + "$ref": "#/$defs/Squash_Reference_" + }, + { + "$ref": "#/$defs/Line_Reference_" + }, + { + "$ref": "#/$defs/Static_Reference_" + }, + { + "$ref": "#/$defs/Spiral_Reference_" + } + ] + }, + "Spiral_Reference_": { + "additionalProperties": false, + "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n from scanspec.specs import Spiral\n\n spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)", + "properties": { + "x_axis": { + "description": "An identifier for what to move for x", + "title": "X Axis", + "type": "bluesky.protocols.Movable" + }, + "y_axis": { + "description": "An identifier for what to move for y", + "title": "Y Axis", + "type": "bluesky.protocols.Movable" + }, + "x_start": { + "description": "x centre of the spiral", + "title": "X Start", + "type": "number" + }, + "y_start": { + "description": "y centre of the spiral", + "title": "Y Start", + "type": "number" + }, + "x_range": { + "description": "x width of the spiral", + "title": "X Range", + "type": "number" + }, + "y_range": { + "description": "y width of the spiral", + "title": "Y Range", + "type": "number" + }, + "num": { + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "rotate": { + "default": 0, + "description": "How much to rotate the angle of the spiral", + "title": "Rotate", + "type": "number" + }, + "type": { + "const": "Spiral", + "default": "Spiral", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_start", + "y_start", + "x_range", + "y_range", + "num" + ], + "title": "Spiral", + "type": "object" + }, + "Squash_Reference_": { + "additionalProperties": false, + "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n `why-squash-can-change-path`\n\n.. example_spec::\n\n from scanspec.specs import Line, Squash\n\n spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))", + "properties": { + "spec": { + "$ref": "#/$defs/Spec", + "description": "The Spec to squash the dimensions of" + }, + "check_path_changes": { + "default": true, + "description": "If True path through scan will not be modified by squash", + "title": "Check Path Changes", + "type": "boolean" + }, + "type": { + "const": "Squash", + "default": "Squash", + "title": "Type", + "type": "string" + } + }, + "required": [ + "spec" + ], + "title": "Squash", + "type": "object" + }, + "Static_Reference_": { + "additionalProperties": false, + "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n from scanspec.specs import Line, Static\n\n spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))", + "properties": { + "axis": { + "description": "An identifier for what to move", + "title": "Axis", + "type": "bluesky.protocols.Movable" + }, + "value": { + "description": "The value at each point", + "title": "Value", + "type": "number" + }, + "num": { + "default": 1, + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "type": { + "const": "Static", + "default": "Static", + "title": "Type", + "type": "string" + } + }, + "required": [ + "axis", + "value" + ], + "title": "Static", + "type": "object" + }, + "SymmetricDifferenceOf_Reference_": { + "additionalProperties": false, + "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, True, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "SymmetricDifferenceOf", + "default": "SymmetricDifferenceOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "SymmetricDifferenceOf", + "type": "object" + }, + "UnionOf_Reference_": { + "additionalProperties": false, + "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, True, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "UnionOf", + "default": "UnionOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "UnionOf", + "type": "object" + }, + "Zip_Reference_": { + "additionalProperties": false, + "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))", + "properties": { + "left": { + "$ref": "#/$defs/Spec", + "description": "The left-hand Spec to Zip, will appear earlier in axes" + }, + "right": { + "$ref": "#/$defs/Spec", + "description": "The right-hand Spec to Zip, will appear later in axes" + }, + "type": { + "const": "Zip", + "default": "Zip", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "Zip", + "type": "object" + } }, - { - "name": "set_absolute", - "description": "\n Set a device, wrapper for `bp.abs_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "movable": { - "title": "Movable", - "type": "bluesky.protocols.Movable" - }, - "value": { - "title": "Value" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - }, - "wait": { - "title": "Wait", - "type": "boolean" - } - }, - "required": [ - "movable", - "value" - ], - "title": "set_absolute", + "additionalProperties": false, + "properties": { + "detectors": { + "items": { + "type": "bluesky.protocols.Readable" + }, + "title": "Detectors", + "type": "array", + "uniqueItems": true + }, + "spec": { + "$ref": "#/$defs/Spec" + }, + "metadata": { + "anyOf": [ + { "type": "object" - } + }, + { + "type": "null" + } + ], + "title": "Metadata" + } }, - { - "name": "set_relative", - "description": "\n Change a device, wrapper for `bp.rel_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "movable": { - "title": "Movable", - "type": "bluesky.protocols.Movable" - }, - "value": { - "title": "Value" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - }, - "wait": { - "title": "Wait", - "type": "boolean" - } - }, - "required": [ - "movable", - "value" - ], - "title": "set_relative", - "type": "object" - } + "required": [ + "detectors", + "spec" + ], + "title": "spec_scan", + "type": "object" + } + }, + { + "name": "set_absolute", + "description": "\n Set a device, wrapper for `bp.abs_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "schema": { + "additionalProperties": false, + "properties": { + "movable": { + "title": "Movable", + "type": "bluesky.protocols.Movable" + }, + "value": { + "title": "Value" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + }, + "wait": { + "title": "Wait", + "type": "boolean" + } }, - { - "name": "move_relative", - "description": "\n Move a device relative to its current position, wrapper for `bp.mvr`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target deltas\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "moves": { - "title": "Moves", - "type": "object" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - } - }, - "required": [ - "moves" - ], - "title": "move_relative", - "type": "object" - } + "required": [ + "movable", + "value" + ], + "title": "set_absolute", + "type": "object" + } + }, + { + "name": "set_relative", + "description": "\n Change a device, wrapper for `bp.rel_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "schema": { + "additionalProperties": false, + "properties": { + "movable": { + "title": "Movable", + "type": "bluesky.protocols.Movable" + }, + "value": { + "title": "Value" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + }, + "wait": { + "title": "Wait", + "type": "boolean" + } }, - { - "name": "sleep", - "description": "\n Suspend all action for a given time, wrapper for `bp.sleep`\n\n Args:\n time (float): Time to wait in seconds\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "time": { - "title": "Time", - "type": "number" - } - }, - "required": [ - "time" - ], - "title": "sleep", - "type": "object" - } + "required": [ + "movable", + "value" + ], + "title": "set_relative", + "type": "object" + } + }, + { + "name": "move", + "description": "\n Move a device, wrapper for `bp.mv`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target positions\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "schema": { + "additionalProperties": false, + "properties": { + "moves": { + "title": "Moves", + "type": "object" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + } }, - { - "name": "wait", - "description": "\n Wait for a group status to complete, wrapper for `bp.wait`.\n Does not expose move_on, as when used as a stub will not fail on Timeout.\n\n Args:\n group (Group | None, optional): The name of the group to wait for, defaults\n to None, in which case waits for all\n groups that have not yet been awaited.\n timeout (float | None, default=None): a timeout in seconds\n\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "parameter_schema": { - "additionalProperties": false, - "properties": { - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - }, - "timeout": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "title": "Timeout" - } - }, - "title": "wait", - "type": "object" - } - } - ] + "required": [ + "moves" + ], + "title": "move", + "type": "object" + } + }, + { + "name": "move_relative", + "description": "\n Move a device relative to its current position, wrapper for `bp.mvr`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target deltas\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "schema": { + "additionalProperties": false, + "properties": { + "moves": { + "title": "Moves", + "type": "object" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + } + }, + "required": [ + "moves" + ], + "title": "move_relative", + "type": "object" + } + }, + { + "name": "sleep", + "description": "\n Suspend all action for a given time, wrapper for `bp.sleep`\n\n Args:\n time (float): Time to wait in seconds\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "schema": { + "additionalProperties": false, + "properties": { + "time": { + "title": "Time", + "type": "number" + } + }, + "required": [ + "time" + ], + "title": "sleep", + "type": "object" + } + }, + { + "name": "wait", + "description": "\n Wait for a group status to complete, wrapper for `bp.wait`.\n Does not expose move_on, as when used as a stub will not fail on Timeout.\n\n Args:\n group (Group | None, optional): The name of the group to wait for, defaults\n to None, in which case waits for all\n groups that have not yet been awaited.\n timeout (float | None, default=None): a timeout in seconds\n\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "schema": { + "additionalProperties": false, + "properties": { + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + }, + "timeout": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Timeout" + } + }, + "title": "wait", + "type": "object" + } + } + ] } diff --git a/tests/system_tests/test_blueapi_system.py b/tests/system_tests/test_blueapi_system.py index f3e02098b..cf9bb4fde 100644 --- a/tests/system_tests/test_blueapi_system.py +++ b/tests/system_tests/test_blueapi_system.py @@ -149,7 +149,7 @@ def test_get_plans(client: BlueapiClient, expected_plans: PlanResponse): retrieved_plans.plans.sort(key=lambda x: x.name) expected_plans.plans.sort(key=lambda x: x.name) - assert retrieved_plans == expected_plans + assert retrieved_plans.model_dump() == expected_plans.model_dump() def test_get_plans_by_name(client: BlueapiClient, expected_plans: PlanResponse): @@ -355,6 +355,7 @@ def test_delete_current_environment(client: BlueapiClient): assert new_env.error_message is None +@pytest.mark.xfail() @pytest.mark.parametrize( "task", [ @@ -368,15 +369,20 @@ def test_delete_current_environment(client: BlueapiClient): "num": 5, }, ), - Task( - name="spec_scan", - params={ - "detectors": [ - "image_det", - "current_det", - ], - "spec": Line("x", 0.0, 10.0, 10) * Line("y", 5.0, 15.0, 20), - }, + pytest.param( + Task( + name="spec_scan", + params={ + "detectors": [ + "image_det", + "current_det", + ], + "spec": Line("x", 0.0, 10.0, 10) * Line("y", 5.0, 15.0, 20), + }, + ), + marks=pytest.mark.xfail( + reason="https://github.com/DiamondLightSource/blueapi/issues/782" + ), ), ], ) From 3b3a2289aa30e943d43fc5e26983533ab3cc11ce Mon Sep 17 00:00:00 2001 From: Callum Forrester Date: Mon, 3 Feb 2025 14:48:39 +0000 Subject: [PATCH 5/5] Revert changes to plans --- tests/system_tests/plans.json | 2201 ++++++++++++++++----------------- 1 file changed, 1094 insertions(+), 1107 deletions(-) diff --git a/tests/system_tests/plans.json b/tests/system_tests/plans.json index dc4f9865c..5fe8259dc 100644 --- a/tests/system_tests/plans.json +++ b/tests/system_tests/plans.json @@ -1,1121 +1,1108 @@ { - "plans": [ - { - "name": "stp_snapshot", - "description": "\n Moves devices for pressure and temperature (defaults fetched from the context)\n and captures a single frame from a collection of devices\n\n Args:\n detectors (List[Readable]): A list of devices to read while the sample is at STP\n temperature (Optional[Movable]): A device controlling temperature of the sample,\n defaults to fetching a device name \"sample_temperature\" from the context\n pressure (Optional[Movable]): A device controlling pressure on the sample,\n defaults to fetching a device name \"sample_pressure\" from the context\n Returns:\n MsgGenerator: Plan\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "schema": { - "additionalProperties": false, - "properties": { - "detectors": { - "items": { - "type": "bluesky.protocols.Readable" - }, - "title": "Detectors", - "type": "array" - }, - "temperature": { - "title": "Temperature", - "type": "bluesky.protocols.Movable" - }, - "pressure": { - "title": "Pressure", - "type": "bluesky.protocols.Movable" - } - }, - "required": [ - "detectors" - ], - "title": "stp_snapshot", - "type": "object" - } - }, - { - "name": "count", - "description": "Reads from a number of devices.\n Wraps bluesky.plans.count(det, num, delay, md=metadata) exposing only serializable\n parameters and metadata.", - "schema": { - "additionalProperties": false, - "properties": { - "detectors": { - "items": { - "type": "bluesky.protocols.Readable" - }, - "title": "Detectors", - "type": "array", - "uniqueItems": true - }, - "num": { - "title": "Num", - "type": "integer" - }, - "delay": { - "anyOf": [ - { - "type": "number" - }, - { - "items": { - "type": "number" + "plans": [ + { + "name": "move", + "description": "\n Move a device, wrapper for `bp.mv`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target positions\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "moves": { + "title": "Moves", + "type": "object" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + } }, - "type": "array" - } - ], - "title": "Delay" - }, - "metadata": { - "anyOf": [ - { + "required": [ + "moves" + ], + "title": "move", "type": "object" - }, - { - "type": "null" - } - ], - "title": "Metadata" - } + } }, - "required": [ - "detectors" - ], - "title": "count", - "type": "object" - } - }, - { - "name": "spec_scan", - "description": "Generic plan for reading `detectors` at every point of a ScanSpec `Spec`.\n A `Spec` is an N-dimensional path.\n ", - "schema": { - "$defs": { - "Circle_Reference_": { - "additionalProperties": false, - "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis", - "type": "bluesky.protocols.Movable" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis", - "type": "bluesky.protocols.Movable" - }, - "x_middle": { - "description": "The central x point of the circle", - "title": "X Middle", - "type": "number" - }, - "y_middle": { - "description": "The central y point of the circle", - "title": "Y Middle", - "type": "number" - }, - "radius": { - "description": "Radius of the circle", - "exclusiveMinimum": 0, - "title": "Radius", - "type": "number" - }, - "type": { - "const": "Circle", - "default": "Circle", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_middle", - "y_middle", - "radius" - ], - "title": "Circle", - "type": "object" - }, - "CombinationOf_Reference_": { - "additionalProperties": false, - "description": "Abstract baseclass for a combination of two regions, left and right.", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "CombinationOf", - "default": "CombinationOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "CombinationOf", - "type": "object" - }, - "Concat_Reference_": { - "additionalProperties": false, - "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))", - "properties": { - "left": { - "$ref": "#/$defs/Spec", - "description": "The left-hand Spec to Concat, midpoints will appear earlier" - }, - "right": { - "$ref": "#/$defs/Spec", - "description": "The right-hand Spec to Concat, midpoints will appear later" - }, - "gap": { - "default": false, - "description": "If True, force a gap in the output at the join", - "title": "Gap", - "type": "boolean" - }, - "check_path_changes": { - "default": true, - "description": "If True path through scan will not be modified by squash", - "title": "Check Path Changes", - "type": "boolean" - }, - "type": { - "const": "Concat", - "default": "Concat", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "Concat", - "type": "object" - }, - "DifferenceOf_Reference_": { - "additionalProperties": false, - "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, False, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "DifferenceOf", - "default": "DifferenceOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "DifferenceOf", - "type": "object" - }, - "Ellipse_Reference_": { - "additionalProperties": false, - "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Ellipse\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis", - "type": "bluesky.protocols.Movable" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis", - "type": "bluesky.protocols.Movable" - }, - "x_middle": { - "description": "The central x point of the ellipse", - "title": "X Middle", - "type": "number" - }, - "y_middle": { - "description": "The central y point of the ellipse", - "title": "Y Middle", - "type": "number" - }, - "x_radius": { - "description": "The radius along the x axis of the ellipse", - "exclusiveMinimum": 0, - "title": "X Radius", - "type": "number" - }, - "y_radius": { - "description": "The radius along the y axis of the ellipse", - "exclusiveMinimum": 0, - "title": "Y Radius", - "type": "number" - }, - "angle": { - "default": 0, - "description": "The angle of the ellipse (degrees)", - "title": "Angle", - "type": "number" - }, - "type": { - "const": "Ellipse", - "default": "Ellipse", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_middle", - "y_middle", - "x_radius", - "y_radius" - ], - "title": "Ellipse", - "type": "object" - }, - "IntersectionOf_Reference_": { - "additionalProperties": false, - "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False, True, False, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "IntersectionOf", - "default": "IntersectionOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "IntersectionOf", - "type": "object" - }, - "Line_Reference_": { - "additionalProperties": false, - "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 2, 5)", - "properties": { - "axis": { - "description": "An identifier for what to move", - "title": "Axis", - "type": "bluesky.protocols.Movable" - }, - "start": { - "description": "Midpoint of the first point of the line", - "title": "Start", - "type": "number" - }, - "stop": { - "description": "Midpoint of the last point of the line", - "title": "Stop", - "type": "number" - }, - "num": { - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "type": { - "const": "Line", - "default": "Line", - "title": "Type", - "type": "string" - } - }, - "required": [ - "axis", - "start", - "stop", - "num" - ], - "title": "Line", - "type": "object" - }, - "Mask_Reference_": { - "additionalProperties": false, - "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`", - "properties": { - "spec": { - "$ref": "#/$defs/Spec", - "description": "The Spec containing the source midpoints" - }, - "region": { - "$ref": "#/$defs/Region", - "description": "The Region that midpoints will be inside" - }, - "check_path_changes": { - "default": true, - "description": "If True path through scan will not be modified by squash", - "title": "Check Path Changes", - "type": "boolean" - }, - "type": { - "const": "Mask", - "default": "Mask", - "title": "Type", - "type": "string" - } - }, - "required": [ - "spec", - "region" - ], - "title": "Mask", - "type": "object" - }, - "Polygon_Reference_": { - "additionalProperties": false, - "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n from scanspec.regions import Polygon\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis", - "type": "bluesky.protocols.Movable" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis", - "type": "bluesky.protocols.Movable" - }, - "x_verts": { - "description": "The Nx1 x coordinates of the polygons vertices", - "items": { - "type": "number" - }, - "minItems": 3, - "title": "X Verts", - "type": "array" - }, - "y_verts": { - "description": "The Nx1 y coordinates of the polygons vertices", - "items": { - "type": "number" + { + "name": "count", + "description": "Reads from a number of devices.\n Wraps bluesky.plans.count(det, num, delay, md=metadata) exposing only serializable\n parameters and metadata.", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "detectors": { + "items": { + "type": "bluesky.protocols.Readable" + }, + "title": "Detectors", + "type": "array", + "uniqueItems": true + }, + "num": { + "title": "Num", + "type": "integer" + }, + "delay": { + "anyOf": [ + { + "type": "number" + }, + { + "items": { + "type": "number" + }, + "type": "array" + } + ], + "title": "Delay" + }, + "metadata": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Metadata" + } }, - "minItems": 3, - "title": "Y Verts", - "type": "array" - }, - "type": { - "const": "Polygon", - "default": "Polygon", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_verts", - "y_verts" - ], - "title": "Polygon", - "type": "object" - }, - "Product_Reference_": { - "additionalProperties": false, - "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)", - "properties": { - "outer": { - "$ref": "#/$defs/Spec", - "description": "Will be executed once" - }, - "inner": { - "$ref": "#/$defs/Spec", - "description": "Will be executed len(outer) times" - }, - "type": { - "const": "Product", - "default": "Product", - "title": "Type", - "type": "string" - } - }, - "required": [ - "outer", - "inner" - ], - "title": "Product", - "type": "object" - }, - "Range_Reference_": { - "additionalProperties": false, - "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, False, False])", - "properties": { - "axis": { - "description": "The name matching the axis to mask in spec", - "title": "Axis", - "type": "bluesky.protocols.Movable" - }, - "min": { - "description": "The minimum inclusive value in the region", - "title": "Min", - "type": "number" - }, - "max": { - "description": "The minimum inclusive value in the region", - "title": "Max", - "type": "number" - }, - "type": { - "const": "Range", - "default": "Range", - "title": "Type", - "type": "string" - } - }, - "required": [ - "axis", - "min", - "max" - ], - "title": "Range", - "type": "object" - }, - "Rectangle_Reference_": { - "additionalProperties": false, - "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n from scanspec.regions import Rectangle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)", - "properties": { - "x_axis": { - "description": "The name matching the x axis of the spec", - "title": "X Axis", - "type": "bluesky.protocols.Movable" - }, - "y_axis": { - "description": "The name matching the y axis of the spec", - "title": "Y Axis", - "type": "bluesky.protocols.Movable" - }, - "x_min": { - "description": "Minimum inclusive x value in the region", - "title": "X Min", - "type": "number" - }, - "y_min": { - "description": "Minimum inclusive y value in the region", - "title": "Y Min", - "type": "number" - }, - "x_max": { - "description": "Maximum inclusive x value in the region", - "title": "X Max", - "type": "number" - }, - "y_max": { - "description": "Maximum inclusive y value in the region", - "title": "Y Max", - "type": "number" - }, - "angle": { - "default": 0, - "description": "Clockwise rotation angle of the rectangle", - "title": "Angle", - "type": "number" - }, - "type": { - "const": "Rectangle", - "default": "Rectangle", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_min", - "y_min", - "x_max", - "y_max" - ], - "title": "Rectangle", - "type": "object" - }, - "Region": { - "discriminator": { - "mapping": { - "Circle": "#/$defs/Circle_Reference_", - "CombinationOf": "#/$defs/CombinationOf_Reference_", - "DifferenceOf": "#/$defs/DifferenceOf_Reference_", - "Ellipse": "#/$defs/Ellipse_Reference_", - "IntersectionOf": "#/$defs/IntersectionOf_Reference_", - "Polygon": "#/$defs/Polygon_Reference_", - "Range": "#/$defs/Range_Reference_", - "Rectangle": "#/$defs/Rectangle_Reference_", - "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf_Reference_", - "UnionOf": "#/$defs/UnionOf_Reference_" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/CombinationOf_Reference_" - }, - { - "$ref": "#/$defs/UnionOf_Reference_" - }, - { - "$ref": "#/$defs/IntersectionOf_Reference_" - }, - { - "$ref": "#/$defs/DifferenceOf_Reference_" - }, - { - "$ref": "#/$defs/SymmetricDifferenceOf_Reference_" - }, - { - "$ref": "#/$defs/Range_Reference_" - }, - { - "$ref": "#/$defs/Rectangle_Reference_" - }, - { - "$ref": "#/$defs/Polygon_Reference_" - }, - { - "$ref": "#/$defs/Circle_Reference_" - }, - { - "$ref": "#/$defs/Ellipse_Reference_" - } - ] - }, - "Repeat_Reference_": { - "additionalProperties": false, - "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n from scanspec.specs import Line, Repeat\n\n spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4", - "properties": { - "num": { - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "gap": { - "default": true, - "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap", - "title": "Gap", - "type": "boolean" - }, - "type": { - "const": "Repeat", - "default": "Repeat", - "title": "Type", - "type": "string" - } - }, - "required": [ - "num" - ], - "title": "Repeat", - "type": "object" - }, - "Snake_Reference_": { - "additionalProperties": false, - "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)", - "properties": { - "spec": { - "$ref": "#/$defs/Spec", - "description": "The Spec to run in reverse every other iteration" - }, - "type": { - "const": "Snake", - "default": "Snake", - "title": "Type", - "type": "string" - } - }, - "required": [ - "spec" - ], - "title": "Snake", - "type": "object" - }, - "Spec": { - "discriminator": { - "mapping": { - "Concat": "#/$defs/Concat_Reference_", - "Line": "#/$defs/Line_Reference_", - "Mask": "#/$defs/Mask_Reference_", - "Product": "#/$defs/Product_Reference_", - "Repeat": "#/$defs/Repeat_Reference_", - "Snake": "#/$defs/Snake_Reference_", - "Spiral": "#/$defs/Spiral_Reference_", - "Squash": "#/$defs/Squash_Reference_", - "Static": "#/$defs/Static_Reference_", - "Zip": "#/$defs/Zip_Reference_" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/Product_Reference_" - }, - { - "$ref": "#/$defs/Repeat_Reference_" - }, - { - "$ref": "#/$defs/Zip_Reference_" - }, - { - "$ref": "#/$defs/Mask_Reference_" - }, - { - "$ref": "#/$defs/Snake_Reference_" - }, - { - "$ref": "#/$defs/Concat_Reference_" - }, - { - "$ref": "#/$defs/Squash_Reference_" - }, - { - "$ref": "#/$defs/Line_Reference_" - }, - { - "$ref": "#/$defs/Static_Reference_" - }, - { - "$ref": "#/$defs/Spiral_Reference_" - } - ] - }, - "Spiral_Reference_": { - "additionalProperties": false, - "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n from scanspec.specs import Spiral\n\n spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)", - "properties": { - "x_axis": { - "description": "An identifier for what to move for x", - "title": "X Axis", - "type": "bluesky.protocols.Movable" - }, - "y_axis": { - "description": "An identifier for what to move for y", - "title": "Y Axis", - "type": "bluesky.protocols.Movable" - }, - "x_start": { - "description": "x centre of the spiral", - "title": "X Start", - "type": "number" - }, - "y_start": { - "description": "y centre of the spiral", - "title": "Y Start", - "type": "number" - }, - "x_range": { - "description": "x width of the spiral", - "title": "X Range", - "type": "number" - }, - "y_range": { - "description": "y width of the spiral", - "title": "Y Range", - "type": "number" - }, - "num": { - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "rotate": { - "default": 0, - "description": "How much to rotate the angle of the spiral", - "title": "Rotate", - "type": "number" - }, - "type": { - "const": "Spiral", - "default": "Spiral", - "title": "Type", - "type": "string" - } - }, - "required": [ - "x_axis", - "y_axis", - "x_start", - "y_start", - "x_range", - "y_range", - "num" - ], - "title": "Spiral", - "type": "object" - }, - "Squash_Reference_": { - "additionalProperties": false, - "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n `why-squash-can-change-path`\n\n.. example_spec::\n\n from scanspec.specs import Line, Squash\n\n spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))", - "properties": { - "spec": { - "$ref": "#/$defs/Spec", - "description": "The Spec to squash the dimensions of" - }, - "check_path_changes": { - "default": true, - "description": "If True path through scan will not be modified by squash", - "title": "Check Path Changes", - "type": "boolean" - }, - "type": { - "const": "Squash", - "default": "Squash", - "title": "Type", - "type": "string" - } - }, - "required": [ - "spec" - ], - "title": "Squash", - "type": "object" - }, - "Static_Reference_": { - "additionalProperties": false, - "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n from scanspec.specs import Line, Static\n\n spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))", - "properties": { - "axis": { - "description": "An identifier for what to move", - "title": "Axis", - "type": "bluesky.protocols.Movable" - }, - "value": { - "description": "The value at each point", - "title": "Value", - "type": "number" - }, - "num": { - "default": 1, - "description": "Number of frames to produce", - "minimum": 1, - "title": "Num", - "type": "integer" - }, - "type": { - "const": "Static", - "default": "Static", - "title": "Type", - "type": "string" - } - }, - "required": [ - "axis", - "value" - ], - "title": "Static", - "type": "object" - }, - "SymmetricDifferenceOf_Reference_": { - "additionalProperties": false, - "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, True, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "SymmetricDifferenceOf", - "default": "SymmetricDifferenceOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "SymmetricDifferenceOf", - "type": "object" - }, - "UnionOf_Reference_": { - "additionalProperties": false, - "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, True, False])", - "properties": { - "left": { - "$ref": "#/$defs/Region", - "description": "The left-hand Region to combine" - }, - "right": { - "$ref": "#/$defs/Region", - "description": "The right-hand Region to combine" - }, - "type": { - "const": "UnionOf", - "default": "UnionOf", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "UnionOf", - "type": "object" - }, - "Zip_Reference_": { - "additionalProperties": false, - "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))", - "properties": { - "left": { - "$ref": "#/$defs/Spec", - "description": "The left-hand Spec to Zip, will appear earlier in axes" - }, - "right": { - "$ref": "#/$defs/Spec", - "description": "The right-hand Spec to Zip, will appear later in axes" - }, - "type": { - "const": "Zip", - "default": "Zip", - "title": "Type", - "type": "string" - } - }, - "required": [ - "left", - "right" - ], - "title": "Zip", - "type": "object" - } - }, - "additionalProperties": false, - "properties": { - "detectors": { - "items": { - "type": "bluesky.protocols.Readable" - }, - "title": "Detectors", - "type": "array", - "uniqueItems": true - }, - "spec": { - "$ref": "#/$defs/Spec" - }, - "metadata": { - "anyOf": [ - { + "required": [ + "detectors" + ], + "title": "count", "type": "object" - }, - { - "type": "null" - } - ], - "title": "Metadata" - } + } }, - "required": [ - "detectors", - "spec" - ], - "title": "spec_scan", - "type": "object" - } - }, - { - "name": "set_absolute", - "description": "\n Set a device, wrapper for `bp.abs_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "schema": { - "additionalProperties": false, - "properties": { - "movable": { - "title": "Movable", - "type": "bluesky.protocols.Movable" - }, - "value": { - "title": "Value" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - }, - "wait": { - "title": "Wait", - "type": "boolean" - } + { + "name": "stp_snapshot", + "description": "\n Moves devices for pressure and temperature (defaults fetched from the context)\n and captures a single frame from a collection of devices\n\n Args:\n detectors (List[Readable]): A list of devices to read while the sample is at STP\n temperature (Optional[Movable]): A device controlling temperature of the sample,\n defaults to fetching a device name \"sample_temperature\" from the context\n pressure (Optional[Movable]): A device controlling pressure on the sample,\n defaults to fetching a device name \"sample_pressure\" from the context\n Returns:\n MsgGenerator: Plan\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "detectors": { + "items": { + "type": "bluesky.protocols.Readable" + }, + "title": "Detectors", + "type": "array" + }, + "temperature": { + "title": "Temperature", + "type": "bluesky.protocols.Movable" + }, + "pressure": { + "title": "Pressure", + "type": "bluesky.protocols.Movable" + } + }, + "required": [ + "detectors" + ], + "title": "stp_snapshot", + "type": "object" + } }, - "required": [ - "movable", - "value" - ], - "title": "set_absolute", - "type": "object" - } - }, - { - "name": "set_relative", - "description": "\n Change a device, wrapper for `bp.rel_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "schema": { - "additionalProperties": false, - "properties": { - "movable": { - "title": "Movable", - "type": "bluesky.protocols.Movable" - }, - "value": { - "title": "Value" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - }, - "wait": { - "title": "Wait", - "type": "boolean" - } + { + "name": "spec_scan", + "description": "Generic plan for reading `detectors` at every point of a ScanSpec `Spec`.\n A `Spec` is an N-dimensional path.\n ", + "parameter_schema": { + "$defs": { + "Circle": { + "additionalProperties": false, + "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis" + }, + "x_middle": { + "description": "The central x point of the circle", + "title": "X Middle", + "type": "number" + }, + "y_middle": { + "description": "The central y point of the circle", + "title": "Y Middle", + "type": "number" + }, + "radius": { + "description": "Radius of the circle", + "exclusiveMinimum": 0.0, + "title": "Radius", + "type": "number" + }, + "type": { + "const": "Circle", + "default": "Circle", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_middle", + "y_middle", + "radius" + ], + "title": "Circle", + "type": "object" + }, + "CombinationOf": { + "additionalProperties": false, + "description": "Abstract baseclass for a combination of two regions, left and right.", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "CombinationOf", + "default": "CombinationOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "CombinationOf", + "type": "object" + }, + "Concat": { + "additionalProperties": false, + "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))", + "properties": { + "left": { + "$ref": "#/$defs/Spec", + "description": "The left-hand Spec to Concat, midpoints will appear earlier" + }, + "right": { + "$ref": "#/$defs/Spec", + "description": "The right-hand Spec to Concat, midpoints will appear later" + }, + "gap": { + "default": false, + "description": "If True, force a gap in the output at the join", + "title": "Gap", + "type": "boolean" + }, + "check_path_changes": { + "default": true, + "description": "If True path through scan will not be modified by squash", + "title": "Check Path Changes", + "type": "boolean" + }, + "type": { + "const": "Concat", + "default": "Concat", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "Concat", + "type": "object" + }, + "DifferenceOf": { + "additionalProperties": false, + "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, False, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "DifferenceOf", + "default": "DifferenceOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "DifferenceOf", + "type": "object" + }, + "Ellipse": { + "additionalProperties": false, + "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n from scanspec.regions import Ellipse\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis" + }, + "x_middle": { + "description": "The central x point of the ellipse", + "title": "X Middle", + "type": "number" + }, + "y_middle": { + "description": "The central y point of the ellipse", + "title": "Y Middle", + "type": "number" + }, + "x_radius": { + "description": "The radius along the x axis of the ellipse", + "exclusiveMinimum": 0.0, + "title": "X Radius", + "type": "number" + }, + "y_radius": { + "description": "The radius along the y axis of the ellipse", + "exclusiveMinimum": 0.0, + "title": "Y Radius", + "type": "number" + }, + "angle": { + "default": 0.0, + "description": "The angle of the ellipse (degrees)", + "title": "Angle", + "type": "number" + }, + "type": { + "const": "Ellipse", + "default": "Ellipse", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_middle", + "y_middle", + "x_radius", + "y_radius" + ], + "title": "Ellipse", + "type": "object" + }, + "IntersectionOf": { + "additionalProperties": false, + "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False, True, False, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "IntersectionOf", + "default": "IntersectionOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "IntersectionOf", + "type": "object" + }, + "Line": { + "additionalProperties": false, + "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"x\", 1, 2, 5)", + "properties": { + "axis": { + "description": "An identifier for what to move", + "title": "Axis" + }, + "start": { + "description": "Midpoint of the first point of the line", + "title": "Start", + "type": "number" + }, + "stop": { + "description": "Midpoint of the last point of the line", + "title": "Stop", + "type": "number" + }, + "num": { + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "type": { + "const": "Line", + "default": "Line", + "title": "Type", + "type": "string" + } + }, + "required": [ + "axis", + "start", + "stop", + "num" + ], + "title": "Line", + "type": "object" + }, + "Mask": { + "additionalProperties": false, + "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n from scanspec.regions import Circle\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`", + "properties": { + "spec": { + "$ref": "#/$defs/Spec", + "description": "The Spec containing the source midpoints" + }, + "region": { + "$ref": "#/$defs/Region", + "description": "The Region that midpoints will be inside" + }, + "check_path_changes": { + "default": true, + "description": "If True path through scan will not be modified by squash", + "title": "Check Path Changes", + "type": "boolean" + }, + "type": { + "const": "Mask", + "default": "Mask", + "title": "Type", + "type": "string" + } + }, + "required": [ + "spec", + "region" + ], + "title": "Mask", + "type": "object" + }, + "Polygon": { + "additionalProperties": false, + "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n from scanspec.regions import Polygon\n from scanspec.specs import Line\n\n grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis" + }, + "x_verts": { + "description": "The Nx1 x coordinates of the polygons vertices", + "items": { + "type": "number" + }, + "minItems": 3, + "title": "X Verts", + "type": "array" + }, + "y_verts": { + "description": "The Nx1 y coordinates of the polygons vertices", + "items": { + "type": "number" + }, + "minItems": 3, + "title": "Y Verts", + "type": "array" + }, + "type": { + "const": "Polygon", + "default": "Polygon", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_verts", + "y_verts" + ], + "title": "Polygon", + "type": "object" + }, + "Product": { + "additionalProperties": false, + "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)", + "properties": { + "outer": { + "$ref": "#/$defs/Spec", + "description": "Will be executed once" + }, + "inner": { + "$ref": "#/$defs/Spec", + "description": "Will be executed len(outer) times" + }, + "type": { + "const": "Product", + "default": "Product", + "title": "Type", + "type": "string" + } + }, + "required": [ + "outer", + "inner" + ], + "title": "Product", + "type": "object" + }, + "Range": { + "additionalProperties": false, + "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, False, False])", + "properties": { + "axis": { + "description": "The name matching the axis to mask in spec", + "title": "Axis" + }, + "min": { + "description": "The minimum inclusive value in the region", + "title": "Min", + "type": "number" + }, + "max": { + "description": "The minimum inclusive value in the region", + "title": "Max", + "type": "number" + }, + "type": { + "const": "Range", + "default": "Range", + "title": "Type", + "type": "string" + } + }, + "required": [ + "axis", + "min", + "max" + ], + "title": "Range", + "type": "object" + }, + "Rectangle": { + "additionalProperties": false, + "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n from scanspec.regions import Rectangle\n from scanspec.specs import Line\n\n grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)", + "properties": { + "x_axis": { + "description": "The name matching the x axis of the spec", + "title": "X Axis" + }, + "y_axis": { + "description": "The name matching the y axis of the spec", + "title": "Y Axis" + }, + "x_min": { + "description": "Minimum inclusive x value in the region", + "title": "X Min", + "type": "number" + }, + "y_min": { + "description": "Minimum inclusive y value in the region", + "title": "Y Min", + "type": "number" + }, + "x_max": { + "description": "Maximum inclusive x value in the region", + "title": "X Max", + "type": "number" + }, + "y_max": { + "description": "Maximum inclusive y value in the region", + "title": "Y Max", + "type": "number" + }, + "angle": { + "default": 0.0, + "description": "Clockwise rotation angle of the rectangle", + "title": "Angle", + "type": "number" + }, + "type": { + "const": "Rectangle", + "default": "Rectangle", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_min", + "y_min", + "x_max", + "y_max" + ], + "title": "Rectangle", + "type": "object" + }, + "Region": { + "discriminator": { + "mapping": { + "Circle": "#/$defs/Circle", + "CombinationOf": "#/$defs/CombinationOf", + "DifferenceOf": "#/$defs/DifferenceOf", + "Ellipse": "#/$defs/Ellipse", + "IntersectionOf": "#/$defs/IntersectionOf", + "Polygon": "#/$defs/Polygon", + "Range": "#/$defs/Range", + "Rectangle": "#/$defs/Rectangle", + "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf", + "UnionOf": "#/$defs/UnionOf" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/CombinationOf" + }, + { + "$ref": "#/$defs/UnionOf" + }, + { + "$ref": "#/$defs/IntersectionOf" + }, + { + "$ref": "#/$defs/DifferenceOf" + }, + { + "$ref": "#/$defs/SymmetricDifferenceOf" + }, + { + "$ref": "#/$defs/Range" + }, + { + "$ref": "#/$defs/Rectangle" + }, + { + "$ref": "#/$defs/Polygon" + }, + { + "$ref": "#/$defs/Circle" + }, + { + "$ref": "#/$defs/Ellipse" + } + ] + }, + "Repeat": { + "additionalProperties": false, + "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n from scanspec.specs import Line, Repeat\n\n spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4", + "properties": { + "num": { + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "gap": { + "default": true, + "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap", + "title": "Gap", + "type": "boolean" + }, + "type": { + "const": "Repeat", + "default": "Repeat", + "title": "Type", + "type": "string" + } + }, + "required": [ + "num" + ], + "title": "Repeat", + "type": "object" + }, + "Snake": { + "additionalProperties": false, + "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)", + "properties": { + "spec": { + "$ref": "#/$defs/Spec", + "description": "The Spec to run in reverse every other iteration" + }, + "type": { + "const": "Snake", + "default": "Snake", + "title": "Type", + "type": "string" + } + }, + "required": [ + "spec" + ], + "title": "Snake", + "type": "object" + }, + "Spec": { + "discriminator": { + "mapping": { + "Concat": "#/$defs/Concat", + "Line": "#/$defs/Line", + "Mask": "#/$defs/Mask", + "Product": "#/$defs/Product", + "Repeat": "#/$defs/Repeat", + "Snake": "#/$defs/Snake", + "Spiral": "#/$defs/Spiral", + "Squash": "#/$defs/Squash", + "Static": "#/$defs/Static", + "Zip": "#/$defs/Zip" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/Product" + }, + { + "$ref": "#/$defs/Repeat" + }, + { + "$ref": "#/$defs/Zip" + }, + { + "$ref": "#/$defs/Mask" + }, + { + "$ref": "#/$defs/Snake" + }, + { + "$ref": "#/$defs/Concat" + }, + { + "$ref": "#/$defs/Squash" + }, + { + "$ref": "#/$defs/Line" + }, + { + "$ref": "#/$defs/Static" + }, + { + "$ref": "#/$defs/Spiral" + } + ] + }, + "Spiral": { + "additionalProperties": false, + "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n from scanspec.specs import Spiral\n\n spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)", + "properties": { + "x_axis": { + "description": "An identifier for what to move for x", + "title": "X Axis" + }, + "y_axis": { + "description": "An identifier for what to move for y", + "title": "Y Axis" + }, + "x_start": { + "description": "x centre of the spiral", + "title": "X Start", + "type": "number" + }, + "y_start": { + "description": "y centre of the spiral", + "title": "Y Start", + "type": "number" + }, + "x_range": { + "description": "x width of the spiral", + "title": "X Range", + "type": "number" + }, + "y_range": { + "description": "y width of the spiral", + "title": "Y Range", + "type": "number" + }, + "num": { + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "rotate": { + "default": 0.0, + "description": "How much to rotate the angle of the spiral", + "title": "Rotate", + "type": "number" + }, + "type": { + "const": "Spiral", + "default": "Spiral", + "title": "Type", + "type": "string" + } + }, + "required": [ + "x_axis", + "y_axis", + "x_start", + "y_start", + "x_range", + "y_range", + "num" + ], + "title": "Spiral", + "type": "object" + }, + "Squash": { + "additionalProperties": false, + "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n `why-squash-can-change-path`\n\n.. example_spec::\n\n from scanspec.specs import Line, Squash\n\n spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))", + "properties": { + "spec": { + "$ref": "#/$defs/Spec", + "description": "The Spec to squash the dimensions of" + }, + "check_path_changes": { + "default": true, + "description": "If True path through scan will not be modified by squash", + "title": "Check Path Changes", + "type": "boolean" + }, + "type": { + "const": "Squash", + "default": "Squash", + "title": "Type", + "type": "string" + } + }, + "required": [ + "spec" + ], + "title": "Squash", + "type": "object" + }, + "Static": { + "additionalProperties": false, + "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n from scanspec.specs import Line, Static\n\n spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))", + "properties": { + "axis": { + "description": "An identifier for what to move", + "title": "Axis" + }, + "value": { + "description": "The value at each point", + "title": "Value", + "type": "number" + }, + "num": { + "default": 1, + "description": "Number of frames to produce", + "minimum": 1, + "title": "Num", + "type": "integer" + }, + "type": { + "const": "Static", + "default": "Static", + "title": "Type", + "type": "string" + } + }, + "required": [ + "axis", + "value" + ], + "title": "Static", + "type": "object" + }, + "SymmetricDifferenceOf": { + "additionalProperties": false, + "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, False, True, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "SymmetricDifferenceOf", + "default": "SymmetricDifferenceOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "SymmetricDifferenceOf", + "type": "object" + }, + "UnionOf": { + "additionalProperties": false, + "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, True, True, True, False])", + "properties": { + "left": { + "$ref": "#/$defs/Region", + "description": "The left-hand Region to combine" + }, + "right": { + "$ref": "#/$defs/Region", + "description": "The right-hand Region to combine" + }, + "type": { + "const": "UnionOf", + "default": "UnionOf", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "UnionOf", + "type": "object" + }, + "Zip": { + "additionalProperties": false, + "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n from scanspec.specs import Line\n\n spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))", + "properties": { + "left": { + "$ref": "#/$defs/Spec", + "description": "The left-hand Spec to Zip, will appear earlier in axes" + }, + "right": { + "$ref": "#/$defs/Spec", + "description": "The right-hand Spec to Zip, will appear later in axes" + }, + "type": { + "const": "Zip", + "default": "Zip", + "title": "Type", + "type": "string" + } + }, + "required": [ + "left", + "right" + ], + "title": "Zip", + "type": "object" + } + }, + "additionalProperties": false, + "properties": { + "detectors": { + "items": { + "type": "bluesky.protocols.Readable" + }, + "title": "Detectors", + "type": "array", + "uniqueItems": true + }, + "spec": { + "$ref": "#/$defs/Spec" + }, + "metadata": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Metadata" + } + }, + "required": [ + "detectors", + "spec" + ], + "title": "spec_scan", + "type": "object" + } }, - "required": [ - "movable", - "value" - ], - "title": "set_relative", - "type": "object" - } - }, - { - "name": "move", - "description": "\n Move a device, wrapper for `bp.mv`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target positions\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "schema": { - "additionalProperties": false, - "properties": { - "moves": { - "title": "Moves", - "type": "object" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - } + { + "name": "set_absolute", + "description": "\n Set a device, wrapper for `bp.abs_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "movable": { + "title": "Movable", + "type": "bluesky.protocols.Movable" + }, + "value": { + "title": "Value" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + }, + "wait": { + "title": "Wait", + "type": "boolean" + } + }, + "required": [ + "movable", + "value" + ], + "title": "set_absolute", + "type": "object" + } }, - "required": [ - "moves" - ], - "title": "move", - "type": "object" - } - }, - { - "name": "move_relative", - "description": "\n Move a device relative to its current position, wrapper for `bp.mvr`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target deltas\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "schema": { - "additionalProperties": false, - "properties": { - "moves": { - "title": "Moves", - "type": "object" - }, - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - } + { + "name": "set_relative", + "description": "\n Change a device, wrapper for `bp.rel_set`.\n\n Args:\n movable (Movable): The device to set\n value (T): The new value\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n wait (bool, optional): The group should wait until all setting is complete\n (e.g. a motor has finished moving). Defaults to False.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "movable": { + "title": "Movable", + "type": "bluesky.protocols.Movable" + }, + "value": { + "title": "Value" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + }, + "wait": { + "title": "Wait", + "type": "boolean" + } + }, + "required": [ + "movable", + "value" + ], + "title": "set_relative", + "type": "object" + } }, - "required": [ - "moves" - ], - "title": "move_relative", - "type": "object" - } - }, - { - "name": "sleep", - "description": "\n Suspend all action for a given time, wrapper for `bp.sleep`\n\n Args:\n time (float): Time to wait in seconds\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "schema": { - "additionalProperties": false, - "properties": { - "time": { - "title": "Time", - "type": "number" - } + { + "name": "move_relative", + "description": "\n Move a device relative to its current position, wrapper for `bp.mvr`.\n\n Args:\n moves (Mapping[Movable, T]): Mapping of Movables to target deltas\n group (Group | None, optional): The message group to associate with the\n setting, for sequencing. Defaults to None.\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "moves": { + "title": "Moves", + "type": "object" + }, + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + } + }, + "required": [ + "moves" + ], + "title": "move_relative", + "type": "object" + } }, - "required": [ - "time" - ], - "title": "sleep", - "type": "object" - } - }, - { - "name": "wait", - "description": "\n Wait for a group status to complete, wrapper for `bp.wait`.\n Does not expose move_on, as when used as a stub will not fail on Timeout.\n\n Args:\n group (Group | None, optional): The name of the group to wait for, defaults\n to None, in which case waits for all\n groups that have not yet been awaited.\n timeout (float | None, default=None): a timeout in seconds\n\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", - "schema": { - "additionalProperties": false, - "properties": { - "group": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Group" - }, - "timeout": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "title": "Timeout" - } + { + "name": "sleep", + "description": "\n Suspend all action for a given time, wrapper for `bp.sleep`\n\n Args:\n time (float): Time to wait in seconds\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "time": { + "title": "Time", + "type": "number" + } + }, + "required": [ + "time" + ], + "title": "sleep", + "type": "object" + } }, - "title": "wait", - "type": "object" - } - } - ] + { + "name": "wait", + "description": "\n Wait for a group status to complete, wrapper for `bp.wait`.\n Does not expose move_on, as when used as a stub will not fail on Timeout.\n\n Args:\n group (Group | None, optional): The name of the group to wait for, defaults\n to None, in which case waits for all\n groups that have not yet been awaited.\n timeout (float | None, default=None): a timeout in seconds\n\n\n Returns:\n MsgGenerator: Plan\n\n Yields:\n Iterator[MsgGenerator]: Bluesky messages\n ", + "parameter_schema": { + "additionalProperties": false, + "properties": { + "group": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Group" + }, + "timeout": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Timeout" + } + }, + "title": "wait", + "type": "object" + } + } + ] }