interloper-api 0.67.0__tar.gz → 0.69.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {interloper_api-0.67.0 → interloper_api-0.69.0}/PKG-INFO +1 -1
  2. {interloper_api-0.67.0 → interloper_api-0.69.0}/pyproject.toml +1 -1
  3. {interloper_api-0.67.0 → interloper_api-0.69.0}/pyproject.toml.orig +1 -1
  4. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/backfills.py +13 -2
  5. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/runs.py +31 -21
  6. {interloper_api-0.67.0 → interloper_api-0.69.0}/README.md +0 -0
  7. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/__init__.py +0 -0
  8. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/app.py +0 -0
  9. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/dependencies/__init__.py +0 -0
  10. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/dependencies/auth.py +0 -0
  11. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/dependencies/rbac.py +0 -0
  12. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/dependencies/state.py +0 -0
  13. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/notifications/__init__.py +0 -0
  14. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/notifications/invitations.py +0 -0
  15. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/__init__.py +0 -0
  16. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/admin.py +0 -0
  17. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/agent.py +0 -0
  18. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/auth.py +0 -0
  19. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/catalog.py +0 -0
  20. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/components.py +0 -0
  21. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/health.py +0 -0
  22. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/oauth.py +0 -0
  23. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/organisations.py +0 -0
  24. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/tokens.py +0 -0
  25. {interloper_api-0.67.0 → interloper_api-0.69.0}/src/interloper_api/routes/websocket.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: interloper-api
3
- Version: 0.67.0
3
+ Version: 0.69.0
4
4
  Summary: Interloper FastAPI routes
5
5
  Author: Guillaume Onfroy
6
6
  Author-email: Guillaume Onfroy <guillaume@digitlcloud.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "interloper-api"
3
- version = "0.67.0"
3
+ version = "0.69.0"
4
4
  description = "Interloper FastAPI routes"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -3,7 +3,7 @@
3
3
  # ###############
4
4
  [project]
5
5
  name = "interloper-api"
6
- version = "0.67.0"
6
+ version = "0.69.0"
7
7
  description = "Interloper FastAPI routes"
8
8
  readme = "README.md"
9
9
  authors = [{ name = "Guillaume Onfroy", email = "guillaume@digitlcloud.com" }]
@@ -36,11 +36,19 @@ class BackfillCreateRequest(BaseModel):
36
36
 
37
37
 
38
38
  class BackfillResponse(BaseModel):
39
- """Response body for a backfill."""
39
+ """Response body for a backfill.
40
+
41
+ The target component's identity is resolved server-side, same contract
42
+ as ``RunResponse``: the ``component_*`` identity fields are ``None``
43
+ exactly when the target was deleted.
44
+ """
40
45
 
41
46
  id: UUID
42
47
  org_id: UUID
43
48
  component_id: UUID | None
49
+ component_kind: str | None = None
50
+ component_key: str | None = None
51
+ component_name: str | None = None
44
52
  status: str
45
53
  start_key: str
46
54
  end_key: str
@@ -56,7 +64,7 @@ class BackfillResponse(BaseModel):
56
64
  """Convert a DB Backfill to a BackfillResponse.
57
65
 
58
66
  Args:
59
- backfill: The DB Backfill row.
67
+ backfill: The DB Backfill row, with its ``target`` relationship loaded.
60
68
 
61
69
  Returns:
62
70
  The response model.
@@ -65,6 +73,9 @@ class BackfillResponse(BaseModel):
65
73
  id=backfill.id,
66
74
  org_id=backfill.org_id,
67
75
  component_id=backfill.component_id,
76
+ component_kind=backfill.target.kind if backfill.target else None,
77
+ component_key=backfill.target.key if backfill.target else None,
78
+ component_name=backfill.target.name if backfill.target else None,
68
79
  status=backfill.status,
69
80
  start_key=backfill.start_key,
70
81
  end_key=backfill.end_key,
@@ -7,7 +7,6 @@ from typing import Annotated, Literal
7
7
  from uuid import UUID
8
8
 
9
9
  from fastapi import APIRouter, Depends, HTTPException, Query, Response
10
- from interloper.component import KINDS
11
10
  from interloper.errors import NotFoundError
12
11
  from interloper_db import Profile, Store
13
12
  from interloper_db.models import Event, Run
@@ -34,11 +33,21 @@ MAX_EVENTS_PAGE_SIZE = 1000
34
33
 
35
34
 
36
35
  class RunResponse(BaseModel):
37
- """Response body for a run."""
36
+ """Response body for a run.
37
+
38
+ The target component's identity is resolved server-side (the row is
39
+ eagerly joined), so clients never need a second lookup — including for
40
+ target kinds they do not know about. All three ``component_*`` identity
41
+ fields are ``None`` exactly when the target was deleted
42
+ (``component_id`` nulls on deletion).
43
+ """
38
44
 
39
45
  id: UUID
40
46
  org_id: UUID
41
47
  component_id: UUID | None
48
+ component_kind: str | None = None
49
+ component_key: str | None = None
50
+ component_name: str | None = None
42
51
  backfill_id: UUID | None
43
52
  partition_key: str | None
44
53
  status: str
@@ -54,7 +63,7 @@ class RunResponse(BaseModel):
54
63
  """Convert a DB Run to a RunResponse.
55
64
 
56
65
  Args:
57
- run: The DB Run row.
66
+ run: The DB Run row, with its ``target`` relationship loaded.
58
67
 
59
68
  Returns:
60
69
  The response model.
@@ -63,6 +72,9 @@ class RunResponse(BaseModel):
63
72
  id=run.id,
64
73
  org_id=run.org_id,
65
74
  component_id=run.component_id,
75
+ component_kind=run.target.kind if run.target else None,
76
+ component_key=run.target.key if run.target else None,
77
+ component_name=run.target.name if run.target else None,
66
78
  backfill_id=run.backfill_id,
67
79
  partition_key=run.partition_key,
68
80
  status=run.status,
@@ -88,13 +100,13 @@ class RetryRequest(BaseModel):
88
100
  scope: Literal["all", "failed"] = "all"
89
101
 
90
102
 
91
- class AssetExecutionResponse(BaseModel):
92
- """Response body for an asset execution (from the asset_executions view)."""
103
+ class ExecutionResponse(BaseModel):
104
+ """Response body for an operation execution (from the ``executions`` view)."""
93
105
 
94
106
  run_id: UUID
95
107
  org_id: UUID
96
- asset_id: UUID | None = None
97
- asset_key: str
108
+ component_id: UUID | None = None
109
+ component_key: str
98
110
  status: str
99
111
  started_at: str | None = None
100
112
  completed_at: str | None = None
@@ -238,7 +250,7 @@ def create_run(
238
250
  user: Profile = Depends(get_current_user),
239
251
  store: Store = Depends(get_store),
240
252
  ) -> RunResponse:
241
- """Queue a single run targeting a runnable component (job, source, or asset).
253
+ """Queue a single run targeting a component whose kind declares an operation.
242
254
 
243
255
  Args:
244
256
  body: The component to run and the partition key to run it for.
@@ -249,12 +261,10 @@ def create_run(
249
261
  The queued run, as a response model.
250
262
 
251
263
  Raises:
252
- HTTPException: 400 if the component's kind is not runnable, or if the
253
- store rejects the run.
264
+ HTTPException: 400 if the store rejects the run (a kind with no
265
+ operation, or an invalid partition key).
254
266
  """
255
267
  target = load_authorized(store.components.get, body.component_id, user, store, label="Component", minimum="editor")
256
- if not KINDS[target.kind].runnable:
257
- raise HTTPException(status_code=400, detail=f"Components of kind '{target.kind}' cannot be run")
258
268
  try:
259
269
  run = store.runs.create(target.org_id, component_id=body.component_id, partition_key=body.partition_key)
260
270
  except ValueError as e:
@@ -282,13 +292,13 @@ def get_run(
282
292
  return RunResponse.from_run(run)
283
293
 
284
294
 
285
- @router.get("/{run_id}/asset-executions")
286
- def list_asset_executions(
295
+ @router.get("/{run_id}/executions")
296
+ def list_executions(
287
297
  run_id: UUID,
288
298
  user: Profile = Depends(get_current_user),
289
299
  store: Store = Depends(get_store),
290
- ) -> list[AssetExecutionResponse]:
291
- """List asset executions for a run.
300
+ ) -> list[ExecutionResponse]:
301
+ """List operation executions for a run.
292
302
 
293
303
  Args:
294
304
  run_id: The run UUID.
@@ -296,16 +306,16 @@ def list_asset_executions(
296
306
  store: The Store instance.
297
307
 
298
308
  Returns:
299
- The run's asset executions, as response models.
309
+ The run's operation executions, as response models.
300
310
  """
301
311
  _load_authorized_run(run_id, user, store)
302
- rows = store.events.list_asset_executions(run_id)
312
+ rows = store.events.list_executions(run_id)
303
313
  return [
304
- AssetExecutionResponse(
314
+ ExecutionResponse(
305
315
  run_id=row.run_id,
306
316
  org_id=row.org_id,
307
- asset_id=row.asset_id,
308
- asset_key=row.asset_key or "",
317
+ component_id=row.component_id,
318
+ component_key=row.component_key or "",
309
319
  status=row.status,
310
320
  started_at=str(row.started_at) if row.started_at else None,
311
321
  completed_at=str(row.completed_at) if row.completed_at else None,