Skip to content

Commit a8fde4e

Browse files
author
Matt Kafonek
authored
Always return list of futures on queue_execution, guard against executing empty code cells (#144)
* Always return list of futures on queue_execution, guard against executing empty code cells * changelog * have queue_execute return dict of future to cell id * fix test * fix changelog
1 parent 599caf5 commit a8fde4e

File tree

3 files changed

+28
-24
lines changed

3 files changed

+28
-24
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ For pre-1.0 releases, see [0.0.35 Changelog](https://github.com/noteable-io/orig
1111
- `origami.models.notebook.make_sql_cell` convenience function, returns a `CodeCell` with appropriate metadata
1212
- `rtu_client.change_cell_type` to switch between code, markdown, and sql cells
1313

14+
### Changed
15+
- `rtu_client.queue_execution` will always return a dict of {Future: cell_id}, even on single cell execution. Also guards against executing empty code cells
16+
1417
## [1.0.0-alpha.2] - 2023-07-26
1518
### Changed
1619
- `api_client.rtu_client` method renamed to `api_client.connect_realtime`, can accept `File` model in addition to `str` / `UUID`

origami/clients/rtu.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import string
1111
import traceback
1212
import uuid
13-
from typing import Awaitable, Callable, Dict, List, Literal, Optional, Type, Union
13+
from typing import Awaitable, Callable, Dict, List, Literal, Optional, Type
1414

1515
import orjson
1616
from pydantic import BaseModel, parse_obj_as
@@ -828,30 +828,29 @@ async def queue_execution(
828828
before_id: Optional[str] = None,
829829
after_id: Optional[str] = None,
830830
run_all: bool = False,
831-
) -> Union[asyncio.Future[CodeCell], List[asyncio.Future[CodeCell]]]:
831+
) -> Dict[asyncio.Future[CodeCell], str]:
832832
"""
833-
Execute an individual cell or multiple cells in the Notebook. The return value is a single
834-
Future or list of Futures that will resolve to the CodeCell executed when the cell has
835-
finished running.
833+
Execute an individual cell or multiple cells in the Notebook. The return value is a dict of
834+
{future: cell_id}, even in the case of executing a single cell.
835+
836836
- Only code Cells can be executed. When running multiple cells with before / after / all
837837
non-code cells will be excluded automatically
838-
- Outputs should be available from the cell.output_collection_id property.
838+
- Code cells with no source are not executed on Noteable backend, so they'll be skipped
839+
- Outputs should be available from the cell.output_collection_id property
840+
841+
Use:
842+
queued_execute = await rtu_client.queue_execution(run_all=True)
843+
done, pending = await asyncio.wait(*queued_execute, timeout=5)
844+
845+
still_running_cell_ids = [queued_execute[f] for f in pending]
839846
"""
840-
# Single cell flow, return a single Future
847+
if not cell_id and not before_id and not after_id and not run_all:
848+
raise ValueError("One of cell_id, before_id, after_id, or run_all must be set.")
849+
841850
if cell_id:
842-
idx, cell = self.builder.get_cell(cell_id) # can raise CellNotFound
843-
if cell.cell_type != 'code':
844-
raise ValueError("Can only queue execute on code cells")
845-
future = asyncio.Future()
846-
self._execute_cell_events[cell_id] = future
851+
cell_ids = [cell_id]
847852
delta = CellExecute(file_id=self.file_id, resource_id=cell_id)
848-
await self.new_delta_request(delta)
849-
return future
850-
851-
# Multiple cell flow
852-
if not before_id and not after_id and not run_all:
853-
raise ValueError("One of cell_id, before_id, after_id, or run_all must be set.")
854-
if before_id:
853+
elif before_id:
855854
idx, cell = self.builder.get_cell(before_id) # can raise CellNotFound
856855
cell_ids = self.cell_ids[: idx + 1] # inclusive of the "before_id" cell
857856
delta = CellExecuteBefore(file_id=self.file_id, resource_id=before_id)
@@ -862,13 +861,14 @@ async def queue_execution(
862861
else:
863862
cell_ids = self.cell_ids[:]
864863
delta = CellExecuteAll(file_id=self.file_id)
865-
futures = []
864+
futures = {}
866865
for cell_id in cell_ids:
867-
# Only create futures for Code cells
866+
# Only create futures for Code cells that have something in source. Otherwise the cell
867+
# will never get executed by PA/Kernel, so we'd never see cell status and resolve future
868868
future = asyncio.Future()
869869
idx, cell = self.builder.get_cell(cell_id)
870-
if cell.cell_type == 'code':
870+
if cell.cell_type == 'code' and cell.source.strip():
871871
self._execute_cell_events[cell_id] = future
872-
futures.append(future)
872+
futures[future] = cell_id
873873
await self.new_delta_request(delta)
874874
return futures

tests/e2e/rtu/test_execution.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ async def test_single_cell(api_client: APIClient, notebook_maker):
2222

2323
queued_execution = await rtu_client.queue_execution('cell_1')
2424
# Assert cell_1 output collection has multiple outputs
25-
cell: CodeCell = await queued_execution # wait for cell_1 to be done
25+
cell_1_fut = list(queued_execution)[0]
26+
cell: CodeCell = await cell_1_fut # wait for cell_1 to be done
2627
output_collection: KernelOutputCollection = await api_client.get_output_collection(
2728
cell.output_collection_id
2829
)

0 commit comments

Comments
 (0)