Skip to content

Commit 0630444

Browse files
authored
[App] Add annotations endpoint (#16159)
1 parent 9657671 commit 0630444

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/lightning_app/core/api.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import asyncio
2+
import json
23
import os
34
import queue
45
import sys
56
import traceback
67
from copy import deepcopy
78
from multiprocessing import Queue
9+
from pathlib import Path
810
from tempfile import TemporaryDirectory
911
from threading import Event, Lock, Thread
1012
from time import sleep
@@ -68,6 +70,7 @@ class SessionMiddleware:
6870

6971
app_spec: Optional[List] = None
7072
app_status: Optional[AppStatus] = None
73+
app_annotations: Optional[List] = None
7174

7275
# In the future, this would be abstracted to support horizontal scaling.
7376
responses_store = {}
@@ -345,6 +348,13 @@ async def get_status() -> AppStatus:
345348
return app_status
346349

347350

351+
@fastapi_service.get("/api/v1/annotations", response_class=JSONResponse)
352+
async def get_annotations() -> Union[List, Dict]:
353+
"""Get the annotations associated with this app."""
354+
global app_annotations
355+
return app_annotations or []
356+
357+
348358
@fastapi_service.get("/healthz", status_code=200)
349359
async def healthz(response: Response):
350360
"""Health check endpoint used in the cloud FastAPI servers to check the status periodically."""
@@ -440,6 +450,7 @@ def start_server(
440450
global api_app_delta_queue
441451
global global_app_state_store
442452
global app_spec
453+
global app_annotations
443454

444455
app_spec = spec
445456
api_app_delta_queue = api_delta_queue
@@ -449,6 +460,12 @@ def start_server(
449460

450461
global_app_state_store.add(TEST_SESSION_UUID)
451462

463+
# Load annotations
464+
annotations_path = Path("lightning-annotations.json").resolve()
465+
if annotations_path.exists():
466+
with open(annotations_path) as f:
467+
app_annotations = json.load(f)
468+
452469
refresher = UIRefresher(api_publish_state_queue, api_response_queue)
453470
refresher.setDaemon(True)
454471
refresher.start()

tests/tests_app/core/test_lightning_api.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import sys
66
from copy import deepcopy
77
from multiprocessing import Process
8+
from pathlib import Path
89
from time import sleep, time
910
from unittest import mock
1011

@@ -562,3 +563,36 @@ def test_configure_api():
562563
time_left -= 0.1
563564
assert process.exitcode == 0
564565
process.kill()
566+
567+
568+
@pytest.mark.anyio
569+
@mock.patch("lightning_app.core.api.UIRefresher", mock.MagicMock())
570+
async def test_get_annotations(tmpdir):
571+
cwd = os.getcwd()
572+
os.chdir(tmpdir)
573+
574+
Path("lightning-annotations.json").write_text('[{"test": 3}]')
575+
576+
try:
577+
app = AppStageTestingApp(FlowA(), log_level="debug")
578+
app._update_layout()
579+
app.stage = AppStage.BLOCKING
580+
change_state_queue = _MockQueue("change_state_queue")
581+
has_started_queue = _MockQueue("has_started_queue")
582+
api_response_queue = _MockQueue("api_response_queue")
583+
spec = extract_metadata_from_app(app)
584+
start_server(
585+
None,
586+
change_state_queue,
587+
api_response_queue,
588+
has_started_queue=has_started_queue,
589+
uvicorn_run=False,
590+
spec=spec,
591+
)
592+
593+
async with AsyncClient(app=fastapi_service, base_url="http://test") as client:
594+
response = await client.get("/api/v1/annotations")
595+
assert response.json() == [{"test": 3}]
596+
finally:
597+
# Cleanup
598+
os.chdir(cwd)

0 commit comments

Comments
 (0)