Skip to content

Commit

Permalink
feat: support paginating attempts across formulations (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtth committed May 27, 2024
1 parent b5111b0 commit 36a6b0c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
53 changes: 52 additions & 1 deletion opvious/client/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,10 @@ async def _track_solve(self, uuid: Uuid) -> Optional[SolveOutcome]:
details.append(f"cuts={ret.cut_count}")
if ret.lp_iteration_count is not None:
details.append(f"iterations={ret.lp_iteration_count}")
_logger.info("Solve is running... [%s]", ", ".join(details))
suffix = ", ".join(details)
_logger.info(
"Solve is running...%s", f" [{suffix}]" if suffix else ""
)
else:
_logger.info("Solve is queued...")
return None
Expand Down Expand Up @@ -698,6 +701,54 @@ async def _outline():
raw_constraints=data["constraints"],
)

async def paginate_solves(
self,
annotations: Optional[list[Annotation]] = None,
limit: int = 25,
) -> AsyncIterator[QueuedSolve]:
"""Lists recent queued solves
Args:
annotations: Optional annotations to filter solves by
limit: Maximum number of solves to return
Solves are sorted from most recently started to least.
"""
cursor = None
attempt_filter = json_dict(
operation="QUEUE_SOLVE",
annotations=encode_annotations(annotations or []),
)

async def _next_page() -> list[QueuedSolve]:
nonlocal cursor
data = await self._executor.execute_graphql_query(
query="@PaginateQueuedSolveAttempts",
variables=json_dict(
last=min(25, limit),
before=cursor,
filter=attempt_filter,
),
)
cursor = data["attempts"]["pageInfo"]["startCursor"]
solves: list[QueuedSolve] = []
for edge in data["attempts"]["edges"]:
attempt = edge["node"]
content = attempt["content"]
if not content:
continue
solves.append(queued_solve_from_graphql(content, attempt))
solves.reverse()
return solves

while limit > 0:
solves = await _next_page()
if not solves:
return
for solve in solves:
yield solve
limit -= len(solves)

async def paginate_formulation_solves(
self,
name: str,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "opvious"
version = "0.19.2rc1"
version = "0.19.2rc2"
description = "Opvious Python SDK"
authors = ["Opvious Engineering <oss@opvious.io>"]
readme = "README.md"
Expand Down
5 changes: 5 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,3 +463,8 @@ async def test_paginate_formulation_solves(self):
async def test_fetch_unknown_solve_outputs(self):
with pytest.raises(opvious.executors.ExecutorError):
await client.fetch_solve_outputs("invalid-uuid")

@pytest.mark.asyncio
async def test_paginate_solves(self):
async for solve in client.paginate_solves(limit=3):
assert isinstance(solve, opvious.QueuedSolve)

0 comments on commit 36a6b0c

Please sign in to comment.