interloper-api 0.28.0__tar.gz → 0.30.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 (24) hide show
  1. {interloper_api-0.28.0 → interloper_api-0.30.0}/PKG-INFO +1 -1
  2. {interloper_api-0.28.0 → interloper_api-0.30.0}/pyproject.toml +1 -1
  3. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/app.py +19 -10
  4. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/dependencies.py +20 -0
  5. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/auth.py +3 -1
  6. {interloper_api-0.28.0 → interloper_api-0.30.0}/README.md +0 -0
  7. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/__init__.py +0 -0
  8. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/email.py +0 -0
  9. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/__init__.py +0 -0
  10. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/admin.py +0 -0
  11. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/agent.py +0 -0
  12. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/assets.py +0 -0
  13. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/backfills.py +0 -0
  14. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/catalog.py +0 -0
  15. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/destinations.py +0 -0
  16. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/external/__init__.py +0 -0
  17. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/external/resolve.py +0 -0
  18. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/jobs.py +0 -0
  19. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/oauth.py +0 -0
  20. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/organisations.py +0 -0
  21. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/resources.py +0 -0
  22. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/runs.py +0 -0
  23. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/sources.py +0 -0
  24. {interloper_api-0.28.0 → interloper_api-0.30.0}/src/interloper_api/routes/ws.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: interloper-api
3
- Version: 0.28.0
3
+ Version: 0.30.0
4
4
  Summary: Interloper FastAPI routes
5
5
  Author: Guillaume Onfroy
6
6
  Author-email: Guillaume Onfroy <guillaume@digitlcloud.com>
@@ -3,7 +3,7 @@
3
3
  # ###############
4
4
  [project]
5
5
  name = "interloper-api"
6
- version = "0.28.0"
6
+ version = "0.30.0"
7
7
  description = "Interloper FastAPI routes"
8
8
  readme = "README.md"
9
9
  authors = [{ name = "Guillaume Onfroy", email = "guillaume@digitlcloud.com" }]
@@ -12,7 +12,7 @@ from interloper.catalog.base import Catalog
12
12
  from interloper.errors import ComponentDriftError
13
13
  from interloper_db import Store
14
14
 
15
- from interloper_api.dependencies import set_auth_config, set_catalog, set_smtp_config, set_store
15
+ from interloper_api.dependencies import set_auth_config, set_catalog, set_features, set_smtp_config, set_store
16
16
  from interloper_api.routes import (
17
17
  admin,
18
18
  assets,
@@ -38,6 +38,7 @@ def create_app(
38
38
  catalog: Catalog | None = None,
39
39
  auth_config: Any | None = None,
40
40
  smtp_config: Any | None = None,
41
+ agent_config: Any | None = None,
41
42
  cors_origins: list[str] | None = None,
42
43
  **kwargs: Any,
43
44
  ) -> FastAPI:
@@ -48,6 +49,8 @@ def create_app(
48
49
  catalog: Catalog instance.
49
50
  auth_config: ``AuthConfig`` instance for authentication settings.
50
51
  smtp_config: ``SmtpConfig`` instance for sending invitation emails.
52
+ agent_config: ``AgentSettings`` instance; the agent routes mount only
53
+ when it's enabled (or None) and the ``agent`` extra is installed.
51
54
  cors_origins: Allowed CORS origins. Only needed in dev mode for direct
52
55
  WebSocket connections that bypass the Vite proxy.
53
56
  **kwargs: Additional kwargs forwarded to ``FastAPI()``.
@@ -100,15 +103,21 @@ def create_app(
100
103
  api.include_router(external.router, prefix="/external", tags=["external"])
101
104
  api.include_router(ws.router, tags=["ws"])
102
105
 
103
- try:
104
- from interloper_api.routes import agent as agent_routes
105
-
106
- api.include_router(agent_routes.router, prefix="/agent", tags=["agent"])
107
- except ImportError:
108
- logger.warning(
109
- "Agent routes not mounted: the 'agent' extra is not installed "
110
- "(install interloper-api[agent]); /agent endpoints will return 404."
111
- )
106
+ agent_available = False
107
+ if agent_config is None or agent_config.enabled:
108
+ try:
109
+ from interloper_api.routes import agent as agent_routes
110
+
111
+ api.include_router(agent_routes.router, prefix="/agent", tags=["agent"])
112
+ agent_available = True
113
+ except ImportError:
114
+ logger.warning(
115
+ "Agent routes not mounted: the 'agent' extra is not installed "
116
+ "(install interloper-api[agent]); /agent endpoints will return 404."
117
+ )
118
+ else:
119
+ logger.info("Agent routes not mounted: disabled via settings.")
120
+ set_features({"agent": agent_available})
112
121
 
113
122
  @api.get("/health")
114
123
  def health() -> dict[str, str]:
@@ -14,6 +14,7 @@ _store: Store | None = None
14
14
  _catalog: Catalog | None = None
15
15
  _auth_config: Any | None = None
16
16
  _smtp_config: Any | None = None
17
+ _features: dict[str, bool] = {}
17
18
 
18
19
  # Role hierarchy: admin > editor > viewer
19
20
  _ROLE_RANK = {"viewer": 0, "editor": 1, "admin": 2}
@@ -112,6 +113,25 @@ def get_smtp_config() -> Any:
112
113
  return _smtp_config
113
114
 
114
115
 
116
+ def set_features(features: dict[str, bool]) -> None:
117
+ """Set the optional-feature availability flags (resolved at app creation).
118
+
119
+ Args:
120
+ features: Feature name → availability.
121
+ """
122
+ global _features # noqa: PLW0603
123
+ _features = features
124
+
125
+
126
+ def get_features() -> dict[str, bool]:
127
+ """Return the optional-feature availability flags.
128
+
129
+ Returns:
130
+ Feature name → availability; empty if never set.
131
+ """
132
+ return _features
133
+
134
+
115
135
  # -- Auth dependencies -------------------------------------------------------
116
136
 
117
137
 
@@ -13,7 +13,7 @@ from fastapi.responses import RedirectResponse
13
13
  from interloper_db import Organisation, Profile, Store
14
14
  from pydantic import BaseModel
15
15
 
16
- from interloper_api.dependencies import get_auth_config, get_current_user, get_store
16
+ from interloper_api.dependencies import get_auth_config, get_current_user, get_features, get_store
17
17
 
18
18
  GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth"
19
19
  GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token"
@@ -41,6 +41,7 @@ class AuthUserResponse(BaseModel):
41
41
  is_super_admin: bool = False
42
42
  organisation: OrganisationResponse | None = None
43
43
  last_organisation_id: UUID | None = None
44
+ features: dict[str, bool] = {}
44
45
 
45
46
 
46
47
  @router.get("/google")
@@ -193,6 +194,7 @@ def get_me(
193
194
  is_super_admin=profile.is_super_admin,
194
195
  organisation=OrganisationResponse.model_validate(org, from_attributes=True) if org else None,
195
196
  last_organisation_id=profile.last_organisation_id,
197
+ features=get_features(),
196
198
  )
197
199
 
198
200