Skip to content

Commit 44863f3

Browse files
committed
Lints, docs and system tests
1 parent 1419f0a commit 44863f3

File tree

3 files changed

+50
-43
lines changed

3 files changed

+50
-43
lines changed

src/blueapi/cli/cli.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from functools import wraps
77
from pathlib import Path
88
from pprint import pprint
9-
from typing import Any
9+
from typing import Any, cast
1010

1111
import click
1212
from bluesky.callbacks.best_effort import BestEffortCallback
@@ -43,18 +43,25 @@
4343

4444

4545
class ParametersType(ParamType):
46+
"""CLI input parameter to accept a JSON object as an argument"""
47+
4648
name = "TaskParameters"
4749

4850
def convert(
4951
self, value: Any, param: Parameter | None, ctx: Context | None
5052
) -> TaskParameters:
5153
if isinstance(value, str):
5254
try:
53-
return json.loads(value)
55+
params = json.loads(value)
56+
if not isinstance(params, dict) or any(
57+
not isinstance(k, str) for k in params
58+
):
59+
self.fail("Parameters must be a JSON object")
60+
return cast(TaskParameters, params)
5461
except json.JSONDecodeError as jde:
5562
self.fail(f"Parameters are not valid JSON: {jde}")
5663
else:
57-
return super().convert(value, param, ctx)
64+
return cast(TaskParameters, super().convert(value, param, ctx))
5865

5966

6067
@click.group(invoke_without_command=True)

src/blueapi/client/client.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def get_active_task(self) -> WorkerTask:
202202
def run_task(
203203
self,
204204
name: str,
205-
parameters: TaskParameters = {},
205+
parameters: TaskParameters | None = None,
206206
*,
207207
on_event: OnAnyEvent | None = None,
208208
timeout: float | None = None,
@@ -226,7 +226,7 @@ def run_task(
226226
"Stomp configuration required to run plans is missing or disabled"
227227
)
228228

229-
task_response = self.create_task(name, parameters)
229+
task_response = self.create_task(name, parameters or {})
230230
task_id = task_response.task_id
231231

232232
complete: Future[WorkerEvent] = Future()
@@ -265,7 +265,7 @@ def inner_on_event(event: AnyEvent, ctx: MessageContext) -> None:
265265

266266
@start_as_current_span(TRACER, "name", "parameters")
267267
def create_and_start_task(
268-
self, name: str, parameters: TaskParameters = {}
268+
self, name: str, parameters: TaskParameters | None = None
269269
) -> TaskResponse:
270270
"""
271271
Create a new task and instruct the worker to start it
@@ -278,7 +278,7 @@ def create_and_start_task(
278278
TaskResponse: Acknowledgement of request
279279
"""
280280

281-
response = self.create_task(name, parameters)
281+
response = self.create_task(name, parameters or {})
282282
worker_response = self.start_task(WorkerTask(task_id=response.task_id))
283283
if worker_response.task_id == response.task_id:
284284
return response
@@ -289,7 +289,7 @@ def create_and_start_task(
289289
)
290290

291291
@start_as_current_span(TRACER, "name", "parameters")
292-
def create_task(self, name: str, parameters: TaskParameters = {}) -> TaskResponse:
292+
def create_task(self, name: str, parameters: TaskParameters) -> TaskResponse:
293293
"""
294294
Create a new task, does not start execution
295295
@@ -303,7 +303,7 @@ def create_task(self, name: str, parameters: TaskParameters = {}) -> TaskRespons
303303
try:
304304
task = Task(name=name, params=parameters)
305305
except ValidationError as ve:
306-
raise InvalidParameters.from_validation_error(ve)
306+
raise InvalidParameters.from_validation_error(ve) from ve
307307
return self._rest.create_task(task)
308308

309309
@start_as_current_span(TRACER)

tests/system_tests/test_blueapi_system.py

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import inspect
22
import time
33
from pathlib import Path
4+
from typing import Any
45

56
import pytest
67
from bluesky_stomp.models import BasicAuthentication
@@ -26,11 +27,10 @@
2627
WorkerTask,
2728
)
2829
from blueapi.worker.event import TaskStatus, WorkerEvent, WorkerState
29-
from blueapi.worker.task import Task
3030
from blueapi.worker.task_worker import TrackableTask
3131

32-
_SIMPLE_TASK = Task(name="sleep", params={"time": 0.0})
33-
_LONG_TASK = Task(name="sleep", params={"time": 1.0})
32+
_SIMPLE_TASK = ("sleep", {"time": 0.0})
33+
_LONG_TASK = ("sleep", {"time": 1.0})
3434

3535
_DATA_PATH = Path(__file__).parent
3636

@@ -182,19 +182,19 @@ def test_get_non_existent_device(client: BlueapiClient):
182182

183183

184184
def test_create_task_and_delete_task_by_id(client: BlueapiClient):
185-
create_task = client.create_task(_SIMPLE_TASK)
185+
create_task = client.create_task(*_SIMPLE_TASK)
186186
client.clear_task(create_task.task_id)
187187

188188

189189
def test_create_task_validation_error(client: BlueapiClient):
190190
with pytest.raises(UnknownPlan):
191-
client.create_task(Task(name="Not-exists", params={"Not-exists": 0.0}))
191+
client.create_task("Not-exists", {"Not-exists": 0.0})
192192

193193

194194
def test_get_all_tasks(client: BlueapiClient):
195195
created_tasks: list[TaskResponse] = []
196196
for task in [_SIMPLE_TASK, _LONG_TASK]:
197-
created_task = client.create_task(task)
197+
created_task = client.create_task(*task)
198198
created_tasks.append(created_task)
199199
task_ids = [task.task_id for task in created_tasks]
200200

@@ -208,7 +208,7 @@ def test_get_all_tasks(client: BlueapiClient):
208208

209209

210210
def test_get_task_by_id(client: BlueapiClient):
211-
created_task = client.create_task(_SIMPLE_TASK)
211+
created_task = client.create_task(*_SIMPLE_TASK)
212212

213213
get_task = client.get_task(created_task.task_id)
214214
assert (
@@ -232,16 +232,16 @@ def test_delete_non_existent_task(client: BlueapiClient):
232232

233233

234234
def test_put_worker_task(client: BlueapiClient):
235-
created_task = client.create_task(_SIMPLE_TASK)
235+
created_task = client.create_task(*_SIMPLE_TASK)
236236
client.start_task(WorkerTask(task_id=created_task.task_id))
237237
active_task = client.get_active_task()
238238
assert active_task.task_id == created_task.task_id
239239
client.clear_task(created_task.task_id)
240240

241241

242242
def test_put_worker_task_fails_if_not_idle(client: BlueapiClient):
243-
small_task = client.create_task(_SIMPLE_TASK)
244-
long_task = client.create_task(_LONG_TASK)
243+
small_task = client.create_task(*_SIMPLE_TASK)
244+
long_task = client.create_task(*_LONG_TASK)
245245

246246
client.start_task(WorkerTask(task_id=long_task.task_id))
247247
active_task = client.get_active_task()
@@ -269,8 +269,8 @@ def test_set_state_transition_error(client: BlueapiClient):
269269

270270

271271
def test_get_task_by_status(client: BlueapiClient):
272-
task_1 = client.create_task(_SIMPLE_TASK)
273-
task_2 = client.create_task(_SIMPLE_TASK)
272+
task_1 = client.create_task(*_SIMPLE_TASK)
273+
task_2 = client.create_task(*_SIMPLE_TASK)
274274
task_by_pending = client.get_all_tasks()
275275
# https://github.com/DiamondLightSource/blueapi/issues/680
276276
# task_by_pending = client.get_tasks_by_status(TaskStatusEnum.PENDING)
@@ -305,7 +305,7 @@ def test_progress_with_stomp(client_with_stomp: BlueapiClient):
305305
def on_event(event: AnyEvent):
306306
all_events.append(event)
307307

308-
client_with_stomp.run_task(_SIMPLE_TASK, on_event=on_event)
308+
client_with_stomp.run_task(*_SIMPLE_TASK, on_event=on_event)
309309
assert isinstance(all_events[0], WorkerEvent) and all_events[0].task_status
310310
task_id = all_events[0].task_status.task_id
311311
assert all_events == [
@@ -350,56 +350,56 @@ def test_delete_current_environment(client: BlueapiClient):
350350

351351

352352
@pytest.mark.parametrize(
353-
"task",
353+
"plan,params",
354354
[
355-
Task(
356-
name="count",
357-
params={
355+
(
356+
"count",
357+
{
358358
"detectors": [
359359
"image_det",
360360
"current_det",
361361
],
362362
"num": 5,
363363
},
364364
),
365-
Task(
366-
name="spec_scan",
367-
params={
365+
(
366+
"spec_scan",
367+
{
368368
"detectors": [
369369
"image_det",
370370
"current_det",
371371
],
372372
"spec": Line("x", 0.0, 10.0, 2) * Line("y", 5.0, 15.0, 3),
373373
},
374374
),
375-
Task(
376-
name="set_absolute",
377-
params={
375+
(
376+
"set_absolute",
377+
{
378378
"movable": "dynamic_motor",
379379
"value": "bar",
380380
},
381381
),
382-
Task(
383-
name="motor_plan",
384-
params={
382+
(
383+
"motor_plan",
384+
{
385385
"motor": "movable_motor",
386386
},
387387
),
388-
Task(
389-
name="motor_plan",
390-
params={
388+
(
389+
"motor_plan",
390+
{
391391
"motor": "dynamic_motor",
392392
},
393393
),
394-
Task(
395-
name="dataclass_motor_plan",
396-
params={
394+
(
395+
"dataclass_motor_plan",
396+
{
397397
"motor": "data_class_motor",
398398
},
399399
),
400400
],
401401
)
402-
def test_plan_runs(client_with_stomp: BlueapiClient, task: Task):
403-
final_event = client_with_stomp.run_task(task)
402+
def test_plan_runs(client_with_stomp: BlueapiClient, plan: str, params: dict[str, Any]):
403+
final_event = client_with_stomp.run_task(plan, params)
404404
assert final_event.is_complete() and not final_event.is_error()
405405
assert final_event.state is WorkerState.IDLE

0 commit comments

Comments
 (0)