graphlagoon 0.8.4__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 (55) hide show
  1. graphlagoon-0.8.4/.env.databricks +17 -0
  2. graphlagoon-0.8.4/.env.databricks-localdb +18 -0
  3. graphlagoon-0.8.4/.env.example +24 -0
  4. graphlagoon-0.8.4/.gitignore +105 -0
  5. graphlagoon-0.8.4/Makefile +22 -0
  6. graphlagoon-0.8.4/PKG-INFO +92 -0
  7. graphlagoon-0.8.4/README.md +47 -0
  8. graphlagoon-0.8.4/alembic/env.py +87 -0
  9. graphlagoon-0.8.4/alembic/script.py.mako +26 -0
  10. graphlagoon-0.8.4/alembic.ini +40 -0
  11. graphlagoon-0.8.4/graphlagoon/__init__.py +114 -0
  12. graphlagoon-0.8.4/graphlagoon/app.py +598 -0
  13. graphlagoon-0.8.4/graphlagoon/cli.py +45 -0
  14. graphlagoon-0.8.4/graphlagoon/config.py +211 -0
  15. graphlagoon-0.8.4/graphlagoon/db/__init__.py +0 -0
  16. graphlagoon-0.8.4/graphlagoon/db/database.py +194 -0
  17. graphlagoon-0.8.4/graphlagoon/db/lakebase.py +308 -0
  18. graphlagoon-0.8.4/graphlagoon/db/memory_store.py +418 -0
  19. graphlagoon-0.8.4/graphlagoon/db/models.py +155 -0
  20. graphlagoon-0.8.4/graphlagoon/main.py +24 -0
  21. graphlagoon-0.8.4/graphlagoon/middleware/__init__.py +0 -0
  22. graphlagoon-0.8.4/graphlagoon/middleware/auth.py +185 -0
  23. graphlagoon-0.8.4/graphlagoon/models/__init__.py +0 -0
  24. graphlagoon-0.8.4/graphlagoon/models/schemas.py +696 -0
  25. graphlagoon-0.8.4/graphlagoon/routers/__init__.py +0 -0
  26. graphlagoon-0.8.4/graphlagoon/routers/catalog.py +144 -0
  27. graphlagoon-0.8.4/graphlagoon/routers/config.py +33 -0
  28. graphlagoon-0.8.4/graphlagoon/routers/explorations.py +664 -0
  29. graphlagoon-0.8.4/graphlagoon/routers/graph.py +891 -0
  30. graphlagoon-0.8.4/graphlagoon/routers/graph_contexts.py +505 -0
  31. graphlagoon-0.8.4/graphlagoon/routers/query_templates.py +281 -0
  32. graphlagoon-0.8.4/graphlagoon/services/__init__.py +0 -0
  33. graphlagoon-0.8.4/graphlagoon/services/cte_prefilter.py +145 -0
  34. graphlagoon-0.8.4/graphlagoon/services/cypher.py +254 -0
  35. graphlagoon-0.8.4/graphlagoon/services/graph_operations.py +335 -0
  36. graphlagoon-0.8.4/graphlagoon/services/sql_validation.py +102 -0
  37. graphlagoon-0.8.4/graphlagoon/services/warehouse.py +1015 -0
  38. graphlagoon-0.8.4/graphlagoon/static/.vite/manifest.json +19 -0
  39. graphlagoon-0.8.4/graphlagoon/static/assets/main-tAVfrLyt.js +8455 -0
  40. graphlagoon-0.8.4/graphlagoon/static/assets/metricsWorker-0-sYkgie.js +1 -0
  41. graphlagoon-0.8.4/graphlagoon/static/assets/roboto-msdf-DyXWe5ZU.png +0 -0
  42. graphlagoon-0.8.4/graphlagoon/static/assets/style-l778HQOh.css +1 -0
  43. graphlagoon-0.8.4/graphlagoon/static/index.html +14 -0
  44. graphlagoon-0.8.4/graphlagoon/templates/index.html +43 -0
  45. graphlagoon-0.8.4/graphlagoon/utils/__init__.py +0 -0
  46. graphlagoon-0.8.4/graphlagoon/utils/sharing.py +72 -0
  47. graphlagoon-0.8.4/pyproject.toml +73 -0
  48. graphlagoon-0.8.4/pyproject.toml.bak +75 -0
  49. graphlagoon-0.8.4/tests/__init__.py +0 -0
  50. graphlagoon-0.8.4/tests/test_catalog_schemas.py +395 -0
  51. graphlagoon-0.8.4/tests/test_cte_prefilter.py +254 -0
  52. graphlagoon-0.8.4/tests/test_graph_error_handling.py +549 -0
  53. graphlagoon-0.8.4/tests/test_sharing_utils.py +184 -0
  54. graphlagoon-0.8.4/tests/test_sql_validation.py +205 -0
  55. graphlagoon-0.8.4/uv.lock +1379 -0
@@ -0,0 +1,17 @@
1
+ # Databricks mode WITHOUT local PostgreSQL
2
+ # Copy to .env and fill in your values
3
+
4
+ # Disable local sql-warehouse - connect directly to Databricks
5
+ GRAPH_LAGOON_DATABRICKS_MODE=true
6
+ GRAPH_LAGOON_DATABRICKS_HOST=adb-XXXXX.X.azuredatabricks.net
7
+ GRAPH_LAGOON_DATABRICKS_TOKEN=dapi-XXXXXXXXXXXXX
8
+ GRAPH_LAGOON_DATABRICKS_WAREHOUSE_ID=XXXXXXXXXXXXXXXX
9
+ GRAPH_LAGOON_DATABRICKS_CATALOG=main
10
+ GRAPH_LAGOON_DATABRICKS_SCHEMA=default
11
+
12
+ # Disable PostgreSQL (contexts/explorations stored in browser localStorage)
13
+ GRAPH_LAGOON_DATABASE_ENABLED=false
14
+
15
+ # General settings
16
+ GRAPH_LAGOON_DEV_MODE=false
17
+ GRAPH_LAGOON_PORT=8000
@@ -0,0 +1,18 @@
1
+ # Databricks mode WITH local PostgreSQL
2
+ # Copy to .env and fill in your values
3
+
4
+ # Connect directly to Databricks SQL Warehouse
5
+ GRAPH_LAGOON_DATABRICKS_MODE=true
6
+ GRAPH_LAGOON_DATABRICKS_HOST=adb-XXXXX.X.azuredatabricks.net
7
+ GRAPH_LAGOON_DATABRICKS_TOKEN=dapi-XXXXXXXXXXXXX
8
+ GRAPH_LAGOON_DATABRICKS_WAREHOUSE_ID=XXXXXXXXXXXXXXXX
9
+ GRAPH_LAGOON_DATABRICKS_CATALOG=main
10
+ GRAPH_LAGOON_DATABRICKS_SCHEMA=default
11
+
12
+ # Use local PostgreSQL for storing contexts/explorations
13
+ GRAPH_LAGOON_DATABASE_ENABLED=true
14
+ GRAPH_LAGOON_DATABASE_URL=postgresql+asyncpg://sgraph:sgraph@localhost:5432/sgraph
15
+
16
+ # General settings
17
+ GRAPH_LAGOON_DEV_MODE=false
18
+ GRAPH_LAGOON_PORT=8000
@@ -0,0 +1,24 @@
1
+ # Graph Lagoon Studio Configuration
2
+ # All variables use GRAPH_LAGOON_ prefix to avoid conflicts with other applications
3
+
4
+ # Local sql-warehouse (dev mode)
5
+ GRAPH_LAGOON_SQL_WAREHOUSE_URL=http://localhost:8001
6
+
7
+ # Database (optional - disabled by default, uses localStorage on frontend)
8
+ # Set GRAPH_LAGOON_DATABASE_ENABLED=true to enable PostgreSQL persistence
9
+ GRAPH_LAGOON_DATABASE_URL=postgresql+asyncpg://sgraph:sgraph@localhost:5432/sgraph
10
+ GRAPH_LAGOON_DATABASE_ENABLED=false
11
+
12
+ # General settings
13
+ GRAPH_LAGOON_DEV_MODE=true
14
+ GRAPH_LAGOON_PORT=8000
15
+
16
+ # Databricks connection (production mode)
17
+ # Set GRAPH_LAGOON_DATABRICKS_MODE=true to connect directly to Databricks
18
+ # When GRAPH_LAGOON_DATABRICKS_MODE=true, CATALOG and SCHEMA are required
19
+ GRAPH_LAGOON_DATABRICKS_MODE=false
20
+ GRAPH_LAGOON_DATABRICKS_HOST=
21
+ GRAPH_LAGOON_DATABRICKS_TOKEN=
22
+ GRAPH_LAGOON_DATABRICKS_WAREHOUSE_ID=
23
+ GRAPH_LAGOON_DATABRICKS_CATALOG=
24
+ GRAPH_LAGOON_DATABRICKS_SCHEMA=
@@ -0,0 +1,105 @@
1
+ scripts/ieee_cis_fraud/data/
2
+ frontend/playwright-report-integration/trace/
3
+ .vitepres
4
+ frontend/ext-3d-force_raw
5
+ frontend/playwright-report-integration/data
6
+ frontend/test-results-integration/.last-run.json
7
+ frontend/test-results-integration
8
+ docs/dew
9
+
10
+ # =============================================================================
11
+ # Project-specific
12
+ # =============================================================================
13
+ frontend/ext-3d-force/exp
14
+ .logs
15
+ .pids
16
+ uv.toml
17
+ metastore_db/
18
+ derby.log
19
+ spark-warehouse/
20
+ alembic/versions/
21
+
22
+ # IDE / Editor
23
+ .vscode
24
+ .idea
25
+ *.swp
26
+
27
+ # Claude Code
28
+ .claude
29
+
30
+ # =============================================================================
31
+ # Python
32
+ # =============================================================================
33
+ __pycache__/
34
+ *.py[codz]
35
+ *$py.class
36
+ *.so
37
+ .Python
38
+ build/
39
+ dist/
40
+ *.egg-info/
41
+ *.egg
42
+ .installed.cfg
43
+ MANIFEST
44
+ .venv
45
+ venv/
46
+ env/
47
+
48
+ # Testing
49
+ htmlcov/
50
+ .tox/
51
+ .nox/
52
+ .coverage
53
+ .coverage.*
54
+ .cache
55
+ .pytest_cache/
56
+ coverage/
57
+ nosetests.xml
58
+ coverage.xml
59
+
60
+ # Type checkers
61
+ .mypy_cache/
62
+ .pytype/
63
+ .ruff_cache/
64
+
65
+ # =============================================================================
66
+ # Node.js
67
+ # =============================================================================
68
+ node_modules/
69
+
70
+ # =============================================================================
71
+ # Environment
72
+ # =============================================================================
73
+ .env
74
+ .envrc
75
+ *.log
76
+
77
+ # =============================================================================
78
+ # OS
79
+ # =============================================================================
80
+ **/.DS_Store
81
+
82
+ # =============================================================================
83
+ # Playwright
84
+ # =============================================================================
85
+ playwright-report/
86
+ test-results/
87
+ frontend/e2e/screenshots/
88
+
89
+ # =============================================================================
90
+ # Performance reports
91
+ # =============================================================================
92
+ frontend/perf-report.json
93
+
94
+ # =============================================================================
95
+ # Build artifacts (generated by make build)
96
+ # =============================================================================
97
+ api/graphlagoon/static/assets/
98
+ api/graphlagoon/static/.vite/
99
+ api/graphlagoon/static/index.html
100
+ CHANGELOG-release.md
101
+
102
+ # =============================================================================
103
+ # Data (warehouse)
104
+ # =============================================================================
105
+ warehouse/data
@@ -0,0 +1,22 @@
1
+ .PHONY: install run dev test clean migrate migrate-create
2
+
3
+ install:
4
+ uv sync
5
+
6
+ run:
7
+ uv run uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload
8
+
9
+ dev: run
10
+
11
+ test:
12
+ uv run pytest -v
13
+
14
+ migrate:
15
+ uv run alembic upgrade head
16
+
17
+ migrate-create:
18
+ uv run alembic revision --autogenerate -m "$(name)"
19
+
20
+ clean:
21
+ rm -rf .venv __pycache__ .pytest_cache
22
+ find . -type d -name "__pycache__" -exec rm -rf {} +
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.4
2
+ Name: graphlagoon
3
+ Version: 0.8.4
4
+ Summary: Graph visualization and exploration tool with FastAPI backend
5
+ Project-URL: Homepage, https://github.com/graphlagoon/graphlagoon
6
+ Project-URL: Documentation, https://github.com/graphlagoon/graphlagoon#readme
7
+ Project-URL: Repository, https://github.com/graphlagoon/graphlagoon
8
+ Author-email: Bruno Messias <devmessias@gmail.com>
9
+ License: AGPL-3.0
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Framework :: FastAPI
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Topic :: Scientific/Engineering :: Visualization
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: asyncpg>=0.31.0
20
+ Requires-Dist: fastapi>=0.109.0
21
+ Requires-Dist: gsql2rsql
22
+ Requires-Dist: httpx>=0.26.0
23
+ Requires-Dist: jinja2>=3.1.0
24
+ Requires-Dist: pydantic-settings>=2.1.0
25
+ Requires-Dist: pydantic>=2.5.0
26
+ Requires-Dist: python-dotenv>=1.0.0
27
+ Requires-Dist: sqlalchemy[asyncio]>=2.0.0
28
+ Requires-Dist: sqlglot>=26.0.0
29
+ Requires-Dist: uvicorn[standard]>=0.27.0
30
+ Provides-Extra: all
31
+ Requires-Dist: alembic>=1.13.0; extra == 'all'
32
+ Requires-Dist: asyncpg>=0.29.0; extra == 'all'
33
+ Requires-Dist: databricks-sdk>=0.38.0; extra == 'all'
34
+ Provides-Extra: dev
35
+ Requires-Dist: debugpy>=1.8.0; extra == 'dev'
36
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
37
+ Requires-Dist: pytest>=7.4.0; extra == 'dev'
38
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
39
+ Provides-Extra: lakebase
40
+ Requires-Dist: databricks-sdk>=0.38.0; extra == 'lakebase'
41
+ Provides-Extra: postgres
42
+ Requires-Dist: alembic>=1.13.0; extra == 'postgres'
43
+ Requires-Dist: asyncpg>=0.29.0; extra == 'postgres'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # Graph Lagoon Studio
47
+
48
+ Graph visualization and exploration tool with FastAPI backend.
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install graphlagoon
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```bash
59
+ # Start the server
60
+ uvicorn graphlagoon.app:app --host 0.0.0.0 --port 8000
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ### Standalone Mode
66
+
67
+ ```python
68
+ from graphlagoon import create_app
69
+
70
+ app = create_app()
71
+ ```
72
+
73
+ ### Embedded Mode
74
+
75
+ ```python
76
+ from fastapi import FastAPI
77
+ from graphlagoon import create_api_router
78
+
79
+ app = FastAPI()
80
+ app.include_router(create_api_router(), prefix="/graphlagoon")
81
+ ```
82
+
83
+ ## Configuration
84
+
85
+ Environment variables:
86
+
87
+ - `DATABASE_ENABLED` - Enable/disable PostgreSQL (default: true)
88
+ - `DATABASE_URL` - PostgreSQL connection string
89
+ - `DATABRICKS_MODE` - Connect to Databricks directly (default: false)
90
+ - `DATABRICKS_HOST` - Databricks workspace host
91
+ - `DATABRICKS_TOKEN` - Databricks access token
92
+ - `DATABRICKS_WAREHOUSE_ID` - SQL warehouse ID
@@ -0,0 +1,47 @@
1
+ # Graph Lagoon Studio
2
+
3
+ Graph visualization and exploration tool with FastAPI backend.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install graphlagoon
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ # Start the server
15
+ uvicorn graphlagoon.app:app --host 0.0.0.0 --port 8000
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### Standalone Mode
21
+
22
+ ```python
23
+ from graphlagoon import create_app
24
+
25
+ app = create_app()
26
+ ```
27
+
28
+ ### Embedded Mode
29
+
30
+ ```python
31
+ from fastapi import FastAPI
32
+ from graphlagoon import create_api_router
33
+
34
+ app = FastAPI()
35
+ app.include_router(create_api_router(), prefix="/graphlagoon")
36
+ ```
37
+
38
+ ## Configuration
39
+
40
+ Environment variables:
41
+
42
+ - `DATABASE_ENABLED` - Enable/disable PostgreSQL (default: true)
43
+ - `DATABASE_URL` - PostgreSQL connection string
44
+ - `DATABRICKS_MODE` - Connect to Databricks directly (default: false)
45
+ - `DATABRICKS_HOST` - Databricks workspace host
46
+ - `DATABRICKS_TOKEN` - Databricks access token
47
+ - `DATABRICKS_WAREHOUSE_ID` - SQL warehouse ID
@@ -0,0 +1,87 @@
1
+ import asyncio
2
+ from logging.config import fileConfig
3
+
4
+ from sqlalchemy import pool
5
+ from sqlalchemy.engine import Connection
6
+ from sqlalchemy.ext.asyncio import async_engine_from_config
7
+
8
+ from alembic import context
9
+
10
+ from graphlagoon.config import get_settings
11
+ from graphlagoon.db.database import Base
12
+
13
+ config = context.config
14
+
15
+ if config.config_file_name is not None:
16
+ fileConfig(config.config_file_name)
17
+
18
+ target_metadata = Base.metadata
19
+
20
+ settings = get_settings()
21
+
22
+ if settings.lakebase_enabled:
23
+ from graphlagoon.db.lakebase import build_lakebase_url
24
+
25
+ config.set_main_option("sqlalchemy.url", build_lakebase_url(settings))
26
+ else:
27
+ config.set_main_option("sqlalchemy.url", settings.database_url)
28
+
29
+
30
+ def run_migrations_offline() -> None:
31
+ """Run migrations in 'offline' mode."""
32
+ url = config.get_main_option("sqlalchemy.url")
33
+ context.configure(
34
+ url=url,
35
+ target_metadata=target_metadata,
36
+ literal_binds=True,
37
+ dialect_opts={"paramstyle": "named"},
38
+ )
39
+
40
+ with context.begin_transaction():
41
+ context.run_migrations()
42
+
43
+
44
+ def do_run_migrations(connection: Connection) -> None:
45
+ context.configure(connection=connection, target_metadata=target_metadata)
46
+
47
+ with context.begin_transaction():
48
+ context.run_migrations()
49
+
50
+
51
+ async def run_async_migrations() -> None:
52
+ """Run migrations in 'online' mode with async engine."""
53
+ engine_kwargs = {}
54
+ if settings.lakebase_enabled:
55
+ server_settings = {"application_name": "graphlagoon-alembic"}
56
+ if settings.default_postgres_schema:
57
+ server_settings["search_path"] = settings.default_postgres_schema
58
+ engine_kwargs["connect_args"] = {
59
+ "ssl": "require",
60
+ "server_settings": server_settings,
61
+ }
62
+
63
+ connectable = async_engine_from_config(
64
+ config.get_section(config.config_ini_section, {}),
65
+ prefix="sqlalchemy.",
66
+ poolclass=pool.NullPool,
67
+ **engine_kwargs,
68
+ )
69
+
70
+ async with connectable.connect() as connection:
71
+ await connection.run_sync(do_run_migrations)
72
+
73
+ await connectable.dispose()
74
+
75
+
76
+ def run_migrations_online() -> None:
77
+ """Run migrations in 'online' mode."""
78
+ asyncio.run(run_async_migrations())
79
+
80
+
81
+ if "connection" in config.attributes:
82
+ # Called programmatically from create_tables() — connection already exists
83
+ do_run_migrations(config.attributes["connection"])
84
+ elif context.is_offline_mode():
85
+ run_migrations_offline()
86
+ else:
87
+ run_migrations_online()
@@ -0,0 +1,26 @@
1
+ """${message}
2
+
3
+ Revision ID: ${up_revision}
4
+ Revises: ${down_revision | comma,n}
5
+ Create Date: ${create_date}
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ ${imports if imports else ""}
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = ${repr(up_revision)}
16
+ down_revision: Union[str, None] = ${repr(down_revision)}
17
+ branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
+ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
+
20
+
21
+ def upgrade() -> None:
22
+ ${upgrades if upgrades else "pass"}
23
+
24
+
25
+ def downgrade() -> None:
26
+ ${downgrades if downgrades else "pass"}
@@ -0,0 +1,40 @@
1
+ [alembic]
2
+ script_location = alembic
3
+ prepend_sys_path = .
4
+ version_path_separator = os
5
+
6
+ [post_write_hooks]
7
+
8
+ [loggers]
9
+ keys = root,sqlalchemy,alembic
10
+
11
+ [handlers]
12
+ keys = console
13
+
14
+ [formatters]
15
+ keys = generic
16
+
17
+ [logger_root]
18
+ level = WARN
19
+ handlers = console
20
+ qualname =
21
+
22
+ [logger_sqlalchemy]
23
+ level = WARN
24
+ handlers =
25
+ qualname = sqlalchemy.engine
26
+
27
+ [logger_alembic]
28
+ level = INFO
29
+ handlers =
30
+ qualname = alembic
31
+
32
+ [handler_console]
33
+ class = StreamHandler
34
+ args = (sys.stderr,)
35
+ level = NOTSET
36
+ formatter = generic
37
+
38
+ [formatter_generic]
39
+ format = %(levelname)-5.5s [%(name)s] %(message)s
40
+ datefmt = %H:%M:%S
@@ -0,0 +1,114 @@
1
+ """Graph Lagoon Studio - Graph visualization and exploration tool for Spark.
2
+
3
+ Usage as standalone app:
4
+ uvicorn graphlagoon.app:app --host 0.0.0.0 --port 8000
5
+
6
+ Usage as importable module (API only):
7
+ from fastapi import FastAPI
8
+ from graphlagoon import create_api_router
9
+
10
+ app = FastAPI()
11
+ app.include_router(create_api_router(), prefix="/api")
12
+
13
+ Usage as mountable sub-app (API + Frontend):
14
+ from fastapi import FastAPI
15
+ from graphlagoon import create_mountable_app, add_mount_redirect
16
+
17
+ app = FastAPI()
18
+ sgraph_app = create_mountable_app(mount_prefix="/graphlagoon")
19
+
20
+ # Add redirect for /graphlagoon -> /graphlagoon/
21
+ add_mount_redirect(app, "/graphlagoon")
22
+
23
+ app.mount("/graphlagoon", sgraph_app)
24
+ # Access at: http://localhost:8000/graphlagoon/
25
+
26
+ Usage with Databricks (specifying catalog and schema):
27
+ from fastapi import FastAPI
28
+ from graphlagoon import create_mountable_app
29
+
30
+ app = FastAPI()
31
+ app.mount("/graphlagoon", create_mountable_app(
32
+ databricks_catalog="my_catalog",
33
+ databricks_schema="my_schema",
34
+ ))
35
+
36
+ Usage with multiple catalog.schema pairs:
37
+ from fastapi import FastAPI
38
+ from graphlagoon import create_mountable_app
39
+
40
+ app = FastAPI()
41
+ app.mount("/graphlagoon", create_mountable_app(
42
+ catalog_schemas=[
43
+ ("catalog_a", "schema_1"),
44
+ ("catalog_b", "schema_2"),
45
+ ],
46
+ ))
47
+
48
+ Usage with dynamic header provider (token refresh):
49
+ from fastapi import FastAPI
50
+ from graphlagoon import create_mountable_app, HeaderProvider
51
+
52
+ # Provider retorna o token (str), não o dict de headers
53
+ async def get_fresh_token() -> str:
54
+ return await my_token_service.get_token()
55
+
56
+ app = FastAPI()
57
+ app.mount("/graphlagoon", create_mountable_app(
58
+ header_provider=get_fresh_token, # Token é convertido para Authorization: Bearer
59
+ databricks_catalog="my_catalog",
60
+ databricks_schema="my_schema",
61
+ ))
62
+
63
+ Usage with custom user provider (integrate with parent app's auth):
64
+ from fastapi import FastAPI, Request
65
+ from graphlagoon import create_mountable_app, UserProvider
66
+
67
+ def get_user_from_parent(request: Request) -> str:
68
+ # Parent app's middleware sets request.state.current_user
69
+ return request.state.current_user.email
70
+
71
+ app = FastAPI()
72
+ app.mount("/graphlagoon", create_mountable_app(
73
+ user_provider=get_user_from_parent,
74
+ databricks_catalog="my_catalog",
75
+ databricks_schema="my_schema",
76
+ ))
77
+ """
78
+
79
+ from graphlagoon.app import (
80
+ create_app,
81
+ create_api_router,
82
+ create_frontend_router,
83
+ create_mountable_app,
84
+ add_mount_redirect,
85
+ )
86
+ from graphlagoon.config import Settings, get_settings
87
+ from graphlagoon.services.warehouse import HeaderProvider
88
+ from graphlagoon.middleware.auth import UserProvider, configure_auth
89
+
90
+ __all__ = [
91
+ "create_app",
92
+ "create_api_router",
93
+ "create_frontend_router",
94
+ "create_mountable_app",
95
+ "add_mount_redirect",
96
+ "Settings",
97
+ "get_settings",
98
+ "HeaderProvider",
99
+ "UserProvider",
100
+ "configure_auth",
101
+ ]
102
+
103
+
104
+ def _get_version() -> str:
105
+ """Read version from pyproject.toml (single source of truth)."""
106
+ from importlib.metadata import version, PackageNotFoundError
107
+
108
+ try:
109
+ return version("graphlagoon")
110
+ except PackageNotFoundError:
111
+ return "0.0.0-dev"
112
+
113
+
114
+ __version__ = _get_version()