interloper-api 0.112.0__tar.gz → 0.113.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.
- {interloper_api-0.112.0 → interloper_api-0.113.0}/PKG-INFO +1 -1
- {interloper_api-0.112.0 → interloper_api-0.113.0}/pyproject.toml +4 -1
- {interloper_api-0.112.0 → interloper_api-0.113.0}/pyproject.toml.orig +4 -1
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/__init__.py +2 -1
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/app.py +4 -4
- interloper_api-0.113.0/src/interloper_api/cli.py +62 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/dependencies/rbac.py +1 -2
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/dependencies/state.py +1 -1
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/admin.py +1 -1
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/auth.py +1 -2
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/catalog.py +3 -4
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/components.py +2 -2
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/overview.py +1 -1
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/tokens.py +1 -2
- interloper_api-0.113.0/src/interloper_api/server.py +72 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/README.md +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/dependencies/__init__.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/dependencies/auth.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/notifications/__init__.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/notifications/base.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/notifications/invitations.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/notifications/super_admins.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/__init__.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/agent.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/backfills.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/executions.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/health.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/oauth.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/organisations.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/relations.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/runs.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/websocket.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/utils/__init__.py +0 -0
- {interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/utils/time.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "interloper-api"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.113.0"
|
|
4
4
|
description = "Interloper FastAPI routes"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -26,6 +26,9 @@ otel = [
|
|
|
26
26
|
"opentelemetry-instrumentation-fastapi>=0.65b0",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
|
+
[project.entry-points."interloper.cli"]
|
|
30
|
+
api = "interloper_api.cli:register"
|
|
31
|
+
|
|
29
32
|
[build-system]
|
|
30
33
|
requires = ["uv_build>=0.12.9,<0.13"]
|
|
31
34
|
build-backend = "uv_build"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# ###############
|
|
4
4
|
[project]
|
|
5
5
|
name = "interloper-api"
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.113.0"
|
|
7
7
|
description = "Interloper FastAPI routes"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
authors = [{ name = "Guillaume Onfroy", email = "guillaume@digitlcloud.com" }]
|
|
@@ -26,6 +26,9 @@ otel = [
|
|
|
26
26
|
"opentelemetry-instrumentation-fastapi>=0.65b0",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
|
+
[project.entry-points."interloper.cli"]
|
|
30
|
+
api = "interloper_api.cli:register"
|
|
31
|
+
|
|
29
32
|
[build-system]
|
|
30
33
|
requires = ["uv_build>=0.12.9,<0.13"]
|
|
31
34
|
build-backend = "uv_build"
|
|
@@ -9,17 +9,17 @@ from typing import Any
|
|
|
9
9
|
from fastapi import APIRouter, FastAPI, Request
|
|
10
10
|
from fastapi.middleware.cors import CORSMiddleware
|
|
11
11
|
from fastapi.responses import JSONResponse
|
|
12
|
-
from interloper.catalog
|
|
13
|
-
from interloper.errors import
|
|
12
|
+
from interloper.catalog import Catalog
|
|
13
|
+
from interloper.errors import ConfigError
|
|
14
|
+
from interloper_db import (
|
|
14
15
|
ComponentDriftError,
|
|
15
|
-
ConfigError,
|
|
16
16
|
ConflictError,
|
|
17
17
|
HydrationError,
|
|
18
18
|
InUseError,
|
|
19
19
|
NotFoundError,
|
|
20
20
|
QuotaExceededError,
|
|
21
|
+
Store,
|
|
21
22
|
)
|
|
22
|
-
from interloper_db import Store
|
|
23
23
|
|
|
24
24
|
from interloper_api.dependencies import (
|
|
25
25
|
set_admin_config,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""``interloper api``: serve the HTTP API, the api role's command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from interloper.catalog import Catalog
|
|
9
|
+
from interloper.cli.console import configure_console_logging
|
|
10
|
+
from interloper.settings import AppSettings
|
|
11
|
+
from interloper.utils import Supervisor
|
|
12
|
+
from interloper_db import Store
|
|
13
|
+
from interloper_db.provision import bootstrap
|
|
14
|
+
|
|
15
|
+
from interloper_api.server import ApiServer
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
19
|
+
"""Register the ``api`` command.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
subparsers: The root subparsers action to attach to.
|
|
23
|
+
"""
|
|
24
|
+
parser = subparsers.add_parser(
|
|
25
|
+
"api",
|
|
26
|
+
help="Serve the HTTP API",
|
|
27
|
+
description="Serve the HTTP API. The frontend is served separately: by nginx in containers, by "
|
|
28
|
+
"`interloper app` locally.",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument("--host", default=None, help="Bind host (default: server.host, 0.0.0.0)")
|
|
31
|
+
parser.add_argument("--port", type=int, default=None, help="Bind port (default: server.port, 3000)")
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--no-create-tables",
|
|
34
|
+
action="store_true",
|
|
35
|
+
default=False,
|
|
36
|
+
help="Skip CREATE TABLE bootstrap on startup (production: run `interloper db init` once instead)",
|
|
37
|
+
)
|
|
38
|
+
parser.set_defaults(handler=_cmd_api)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _cmd_api(args: argparse.Namespace) -> None:
|
|
42
|
+
"""Serve the API until a signal or its death.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
args: Parsed CLI arguments: ``host``, ``port`` and ``no_create_tables``.
|
|
46
|
+
"""
|
|
47
|
+
settings = AppSettings.get()
|
|
48
|
+
if args.host is not None:
|
|
49
|
+
settings = settings.model_copy(update={"server": settings.server.model_copy(update={"host": args.host})})
|
|
50
|
+
AppSettings.activate(settings)
|
|
51
|
+
configure_console_logging(
|
|
52
|
+
logging.INFO, "%(asctime)s %(name)s %(levelname)s %(message)s", log_format=settings.log.format
|
|
53
|
+
)
|
|
54
|
+
bootstrap(
|
|
55
|
+
settings.postgres.dsn,
|
|
56
|
+
statement_timeout=settings.postgres.statement_timeout,
|
|
57
|
+
create_tables=not args.no_create_tables,
|
|
58
|
+
)
|
|
59
|
+
catalog = Catalog.from_settings()
|
|
60
|
+
store = Store.from_settings(catalog=catalog)
|
|
61
|
+
port = settings.server.port if args.port is None else args.port
|
|
62
|
+
Supervisor({"api": ApiServer.from_settings(settings, store=store, catalog=catalog, port=port)}).run()
|
|
@@ -7,8 +7,7 @@ from typing import Annotated, Any
|
|
|
7
7
|
from uuid import UUID
|
|
8
8
|
|
|
9
9
|
from fastapi import Depends, HTTPException
|
|
10
|
-
from
|
|
11
|
-
from interloper_db import Profile, Role, Store
|
|
10
|
+
from interloper_db import NotFoundError, Profile, Role, Store
|
|
12
11
|
|
|
13
12
|
from interloper_api.dependencies.auth import get_current_user, get_org_id
|
|
14
13
|
from interloper_api.dependencies.state import get_store
|
|
@@ -10,7 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
from typing import Annotated, Any
|
|
11
11
|
|
|
12
12
|
from fastapi import Depends
|
|
13
|
-
from interloper.catalog
|
|
13
|
+
from interloper.catalog import Catalog
|
|
14
14
|
from interloper_db import Store
|
|
15
15
|
|
|
16
16
|
_store: Store | None = None
|
|
@@ -541,7 +541,7 @@ def _runner_defaults(runner_type: str) -> dict[str, Any]:
|
|
|
541
541
|
Allowlisted field names mapped to their default value, empty when the
|
|
542
542
|
type is unregistered.
|
|
543
543
|
"""
|
|
544
|
-
from interloper.runner
|
|
544
|
+
from interloper.runner import RUNNERS
|
|
545
545
|
|
|
546
546
|
runner_cls = RUNNERS.get(runner_type)
|
|
547
547
|
if runner_cls is None:
|
|
@@ -11,8 +11,7 @@ from zoneinfo import ZoneInfo
|
|
|
11
11
|
import httpx2
|
|
12
12
|
from fastapi import APIRouter, Cookie, HTTPException, Response
|
|
13
13
|
from fastapi.responses import RedirectResponse
|
|
14
|
-
from
|
|
15
|
-
from interloper_db import Organisation, Profile, Store
|
|
14
|
+
from interloper_db import NotFoundError, Organisation, Profile, Store
|
|
16
15
|
from interloper_db.models import AuthSession
|
|
17
16
|
from pydantic import BaseModel, Field
|
|
18
17
|
|
|
@@ -15,11 +15,10 @@ from typing import Any, Literal, NoReturn
|
|
|
15
15
|
import httpx2
|
|
16
16
|
import interloper as il
|
|
17
17
|
from fastapi import APIRouter, Depends, HTTPException
|
|
18
|
-
from interloper.connection
|
|
18
|
+
from interloper.connection import Connection
|
|
19
19
|
from interloper.errors import ConnectionCheckError, format_exception
|
|
20
|
-
from interloper.resource
|
|
21
|
-
from interloper.utils
|
|
22
|
-
from interloper.utils.imports import import_from_path
|
|
20
|
+
from interloper.resource import is_fetch_field_provider
|
|
21
|
+
from interloper.utils import import_from_path, invoke
|
|
23
22
|
from pydantic import BaseModel, Field, ValidationError
|
|
24
23
|
|
|
25
24
|
from interloper_api.dependencies import CatalogDep, EditorDep, require_viewer
|
|
@@ -24,8 +24,8 @@ from uuid import UUID
|
|
|
24
24
|
|
|
25
25
|
from fastapi import APIRouter, HTTPException, Query, Response
|
|
26
26
|
from interloper.component import KINDS
|
|
27
|
-
from interloper.errors import
|
|
28
|
-
from interloper_db import Component, ComponentQuery, ComponentStatus, DeleteImpact, Page, Store
|
|
27
|
+
from interloper.errors import DataNotFoundError
|
|
28
|
+
from interloper_db import Component, ComponentDriftError, ComponentQuery, ComponentStatus, DeleteImpact, Page, Store
|
|
29
29
|
from pydantic import BaseModel
|
|
30
30
|
|
|
31
31
|
from interloper_api.dependencies import (
|
|
@@ -14,7 +14,7 @@ from typing import Annotated, Literal
|
|
|
14
14
|
from uuid import UUID
|
|
15
15
|
|
|
16
16
|
from fastapi import APIRouter, HTTPException, Query
|
|
17
|
-
from interloper.utils
|
|
17
|
+
from interloper.utils import assume_utc
|
|
18
18
|
from interloper_db import ComponentStatus
|
|
19
19
|
from interloper_db.store import insights
|
|
20
20
|
from pydantic import BaseModel
|
|
@@ -13,8 +13,7 @@ from typing import Annotated
|
|
|
13
13
|
from uuid import UUID
|
|
14
14
|
|
|
15
15
|
from fastapi import APIRouter, HTTPException, Query, Response
|
|
16
|
-
from
|
|
17
|
-
from interloper_db import Page, PageQuery, Role, TokenQuery
|
|
16
|
+
from interloper_db import NotFoundError, Page, PageQuery, Role, TokenQuery
|
|
18
17
|
from pydantic import BaseModel, Field
|
|
19
18
|
|
|
20
19
|
from interloper_api.dependencies import (
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""The API as a supervised service: a uvicorn server over the FastAPI app."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import uvicorn
|
|
8
|
+
from interloper.telemetry import instrument_fastapi
|
|
9
|
+
|
|
10
|
+
from interloper_api.app import create_app
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from fastapi import FastAPI
|
|
14
|
+
from interloper.catalog import Catalog
|
|
15
|
+
from interloper.settings import AppSettings
|
|
16
|
+
from interloper_db import Store
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ApiServer:
|
|
20
|
+
"""The HTTP API, served by uvicorn until stopped.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
app: The FastAPI application; a composing process may add middleware to it before ``start``.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, app: FastAPI, server: uvicorn.Server) -> None:
|
|
27
|
+
"""Hold the application and its server.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
app: The FastAPI application.
|
|
31
|
+
server: The uvicorn server bound to it.
|
|
32
|
+
"""
|
|
33
|
+
self.app = app
|
|
34
|
+
self._server = server
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_settings(
|
|
38
|
+
cls,
|
|
39
|
+
settings: AppSettings,
|
|
40
|
+
*,
|
|
41
|
+
store: Store,
|
|
42
|
+
catalog: Catalog,
|
|
43
|
+
port: int,
|
|
44
|
+
cors_origins: list[str] | None = None,
|
|
45
|
+
) -> ApiServer:
|
|
46
|
+
"""Build the API and its server from settings.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
settings: The active settings; ``server.host`` is the bind host.
|
|
50
|
+
store: The store the routes read and write through.
|
|
51
|
+
catalog: The catalog the routes describe.
|
|
52
|
+
port: The port to bind.
|
|
53
|
+
cors_origins: Origins allowed cross-origin requests; ``None`` allows none
|
|
54
|
+
(dev mode passes the Nuxt dev server's origin).
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
The server, not yet started.
|
|
58
|
+
"""
|
|
59
|
+
app = create_app(store=store, catalog=catalog, settings=settings, cors_origins=cors_origins)
|
|
60
|
+
instrument_fastapi(app)
|
|
61
|
+
config = uvicorn.Config(
|
|
62
|
+
app, host=settings.server.host, port=port, log_level="info", log_config=None, ws="wsproto"
|
|
63
|
+
)
|
|
64
|
+
return cls(app, uvicorn.Server(config))
|
|
65
|
+
|
|
66
|
+
def start(self) -> None:
|
|
67
|
+
"""Serve until stopped."""
|
|
68
|
+
self._server.run()
|
|
69
|
+
|
|
70
|
+
def stop(self) -> None:
|
|
71
|
+
"""Ask the server to finish its requests and return."""
|
|
72
|
+
self._server.should_exit = True
|
|
File without changes
|
{interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/dependencies/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/notifications/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/notifications/invitations.py
RENAMED
|
File without changes
|
{interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/notifications/super_admins.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interloper_api-0.112.0 → interloper_api-0.113.0}/src/interloper_api/routes/organisations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|