minilake 1.5.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 (129) hide show
  1. minilake-1.5.0/.dockerignore +24 -0
  2. minilake-1.5.0/.gitignore +71 -0
  3. minilake-1.5.0/.pre-commit-config.yaml +22 -0
  4. minilake-1.5.0/CONTRIBUTING.md +212 -0
  5. minilake-1.5.0/Dockerfile +40 -0
  6. minilake-1.5.0/Dockerfile.notebook +22 -0
  7. minilake-1.5.0/Dockerfile.test +41 -0
  8. minilake-1.5.0/FEATURES.md +1131 -0
  9. minilake-1.5.0/LICENSE +21 -0
  10. minilake-1.5.0/PKG-INFO +154 -0
  11. minilake-1.5.0/README.md +115 -0
  12. minilake-1.5.0/docker-compose.test.yml +66 -0
  13. minilake-1.5.0/docker-compose.yml +70 -0
  14. minilake-1.5.0/docs/configuration.md +137 -0
  15. minilake-1.5.0/docs/databricks-sdk.md +149 -0
  16. minilake-1.5.0/docs/getting-started.md +127 -0
  17. minilake-1.5.0/docs/index.md +57 -0
  18. minilake-1.5.0/docs/mcp/examples.md +205 -0
  19. minilake-1.5.0/docs/mcp/index.md +86 -0
  20. minilake-1.5.0/docs/mcp/resources-and-prompts.md +68 -0
  21. minilake-1.5.0/docs/mcp/tools.md +93 -0
  22. minilake-1.5.0/docs/mcp/troubleshooting.md +120 -0
  23. minilake-1.5.0/docs/releases.md +109 -0
  24. minilake-1.5.0/docs/spark-and-delta.md +138 -0
  25. minilake-1.5.0/docs/terraform.md +65 -0
  26. minilake-1.5.0/docs/testing.md +90 -0
  27. minilake-1.5.0/examples/terraform/main.tf +106 -0
  28. minilake-1.5.0/examples/terraform/terraform.tfvars.example +10 -0
  29. minilake-1.5.0/examples/terraform/variables.tf +12 -0
  30. minilake-1.5.0/examples/use_as_lib.py +124 -0
  31. minilake-1.5.0/minilake_logo.png +0 -0
  32. minilake-1.5.0/notebooks/minilake_delta_quickstart.ipynb +164 -0
  33. minilake-1.5.0/pyproject.toml +120 -0
  34. minilake-1.5.0/scripts/generate-certs.sh +35 -0
  35. minilake-1.5.0/scripts/run-tests-docker.sh +121 -0
  36. minilake-1.5.0/src/minilake/__init__.py +31 -0
  37. minilake-1.5.0/src/minilake/__main__.py +6 -0
  38. minilake-1.5.0/src/minilake/admin.py +111 -0
  39. minilake-1.5.0/src/minilake/app.py +184 -0
  40. minilake-1.5.0/src/minilake/cli.py +207 -0
  41. minilake-1.5.0/src/minilake/config.py +147 -0
  42. minilake-1.5.0/src/minilake/docker_executor.py +285 -0
  43. minilake-1.5.0/src/minilake/duckdb_pool.py +155 -0
  44. minilake-1.5.0/src/minilake/errors.py +87 -0
  45. minilake-1.5.0/src/minilake/mcp/__init__.py +14 -0
  46. minilake-1.5.0/src/minilake/mcp/client.py +128 -0
  47. minilake-1.5.0/src/minilake/mcp/prompts.py +86 -0
  48. minilake-1.5.0/src/minilake/mcp/resources.py +260 -0
  49. minilake-1.5.0/src/minilake/mcp/server.py +151 -0
  50. minilake-1.5.0/src/minilake/mcp/tools/__init__.py +7 -0
  51. minilake-1.5.0/src/minilake/mcp/tools/admin.py +33 -0
  52. minilake-1.5.0/src/minilake/mcp/tools/clusters.py +61 -0
  53. minilake-1.5.0/src/minilake/mcp/tools/composite.py +188 -0
  54. minilake-1.5.0/src/minilake/mcp/tools/dbfs.py +52 -0
  55. minilake-1.5.0/src/minilake/mcp/tools/files.py +47 -0
  56. minilake-1.5.0/src/minilake/mcp/tools/jobs.py +310 -0
  57. minilake-1.5.0/src/minilake/mcp/tools/secrets.py +45 -0
  58. minilake-1.5.0/src/minilake/mcp/tools/sql.py +146 -0
  59. minilake-1.5.0/src/minilake/mcp/tools/unity_catalog.py +163 -0
  60. minilake-1.5.0/src/minilake/mcp/tools/warehouses.py +48 -0
  61. minilake-1.5.0/src/minilake/mcp/tools/workspace.py +66 -0
  62. minilake-1.5.0/src/minilake/models/__init__.py +1 -0
  63. minilake-1.5.0/src/minilake/models/clusters.py +123 -0
  64. minilake-1.5.0/src/minilake/models/common.py +21 -0
  65. minilake-1.5.0/src/minilake/models/dbfs.py +59 -0
  66. minilake-1.5.0/src/minilake/models/identity.py +23 -0
  67. minilake-1.5.0/src/minilake/models/jobs.py +275 -0
  68. minilake-1.5.0/src/minilake/models/permissions.py +47 -0
  69. minilake-1.5.0/src/minilake/models/secrets.py +44 -0
  70. minilake-1.5.0/src/minilake/models/sql.py +161 -0
  71. minilake-1.5.0/src/minilake/models/unity_catalog.py +245 -0
  72. minilake-1.5.0/src/minilake/models/workspace.py +89 -0
  73. minilake-1.5.0/src/minilake/persistence.py +93 -0
  74. minilake-1.5.0/src/minilake/services/__init__.py +96 -0
  75. minilake-1.5.0/src/minilake/services/catchall.py +32 -0
  76. minilake-1.5.0/src/minilake/services/clusters.py +269 -0
  77. minilake-1.5.0/src/minilake/services/dbfs.py +243 -0
  78. minilake-1.5.0/src/minilake/services/files.py +196 -0
  79. minilake-1.5.0/src/minilake/services/identity.py +40 -0
  80. minilake-1.5.0/src/minilake/services/jobs.py +673 -0
  81. minilake-1.5.0/src/minilake/services/permissions.py +129 -0
  82. minilake-1.5.0/src/minilake/services/secrets.py +133 -0
  83. minilake-1.5.0/src/minilake/services/sql_statements.py +888 -0
  84. minilake-1.5.0/src/minilake/services/sql_warehouses.py +152 -0
  85. minilake-1.5.0/src/minilake/services/unity_catalog.py +960 -0
  86. minilake-1.5.0/src/minilake/services/workspace.py +357 -0
  87. minilake-1.5.0/src/minilake/tls.py +122 -0
  88. minilake-1.5.0/src/minilake/uc_types.py +293 -0
  89. minilake-1.5.0/tests/conftest.py +189 -0
  90. minilake-1.5.0/tests/error_handling/__init__.py +0 -0
  91. minilake-1.5.0/tests/error_handling/test_400_bad_request.py +101 -0
  92. minilake-1.5.0/tests/error_handling/test_404_not_found.py +68 -0
  93. minilake-1.5.0/tests/error_handling/test_501_not_implemented.py +21 -0
  94. minilake-1.5.0/tests/mcp_server/conftest.py +89 -0
  95. minilake-1.5.0/tests/mcp_server/test_capabilities.py +99 -0
  96. minilake-1.5.0/tests/mcp_server/test_errors.py +41 -0
  97. minilake-1.5.0/tests/mcp_server/test_job_tools.py +189 -0
  98. minilake-1.5.0/tests/mcp_server/test_sql_tools.py +73 -0
  99. minilake-1.5.0/tests/mcp_server/test_uc_tools.py +197 -0
  100. minilake-1.5.0/tests/mcp_server/test_workspace_tools.py +73 -0
  101. minilake-1.5.0/tests/test_admin.py +63 -0
  102. minilake-1.5.0/tests/test_app.py +76 -0
  103. minilake-1.5.0/tests/test_clusters.py +156 -0
  104. minilake-1.5.0/tests/test_config.py +71 -0
  105. minilake-1.5.0/tests/test_dbfs.py +94 -0
  106. minilake-1.5.0/tests/test_docker_executor.py +93 -0
  107. minilake-1.5.0/tests/test_files.py +85 -0
  108. minilake-1.5.0/tests/test_golden_path.py +328 -0
  109. minilake-1.5.0/tests/test_identity.py +16 -0
  110. minilake-1.5.0/tests/test_jobs.py +408 -0
  111. minilake-1.5.0/tests/test_models.py +114 -0
  112. minilake-1.5.0/tests/test_permissions.py +79 -0
  113. minilake-1.5.0/tests/test_persistence.py +130 -0
  114. minilake-1.5.0/tests/test_secrets.py +74 -0
  115. minilake-1.5.0/tests/test_sql_statements.py +279 -0
  116. minilake-1.5.0/tests/test_tls.py +72 -0
  117. minilake-1.5.0/tests/test_warehouses.py +78 -0
  118. minilake-1.5.0/tests/test_workspace.py +105 -0
  119. minilake-1.5.0/tests/test_workspace_files.py +81 -0
  120. minilake-1.5.0/tests/unity_catalog/__init__.py +0 -0
  121. minilake-1.5.0/tests/unity_catalog/conftest.py +78 -0
  122. minilake-1.5.0/tests/unity_catalog/test_catalogs.py +130 -0
  123. minilake-1.5.0/tests/unity_catalog/test_delta_tables.py +298 -0
  124. minilake-1.5.0/tests/unity_catalog/test_schemas.py +130 -0
  125. minilake-1.5.0/tests/unity_catalog/test_spark_catalog_protocol.py +138 -0
  126. minilake-1.5.0/tests/unity_catalog/test_tables.py +289 -0
  127. minilake-1.5.0/tests/unity_catalog/test_types.py +146 -0
  128. minilake-1.5.0/tests/unity_catalog/test_volumes.py +65 -0
  129. minilake-1.5.0/uv.lock +2040 -0
@@ -0,0 +1,24 @@
1
+ .git
2
+ .gitignore
3
+ .pytest_cache
4
+ .coverage
5
+ htmlcov
6
+ dist
7
+ build
8
+ *.egg-info
9
+ __pycache__
10
+ *.pyc
11
+ *.pyo
12
+ .venv
13
+ venv
14
+ .env
15
+ .env.*
16
+ !.env.example
17
+ data/
18
+ .certs/
19
+ certs/
20
+ .DS_Store
21
+ Thumbs.db
22
+ docs/
23
+ examples/
24
+ CONTRIBUTING.md
@@ -0,0 +1,71 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ venv/
25
+ env/
26
+ ENV/
27
+ .venv/
28
+
29
+ # Testing
30
+ .pytest_cache/
31
+ .coverage
32
+ htmlcov/
33
+ .tox/
34
+
35
+ # IDE
36
+ .vscode/
37
+ .idea/
38
+ *.swp
39
+ *.swo
40
+ *~
41
+ .DS_Store
42
+
43
+ # minilake specific
44
+ data/
45
+ .certs/
46
+ certs/
47
+ *.duckdb
48
+ *.duckdb.wal
49
+ *.db
50
+
51
+ # Environment
52
+ .env
53
+ .env.local
54
+ .env.*.local
55
+
56
+ # Terraform
57
+ .terraform/
58
+ *.tfstate
59
+ *.tfstate.*
60
+ .terraform.lock.hcl
61
+
62
+ # Docker
63
+ docker-compose.override.yml
64
+
65
+ # OS
66
+ .DS_Store
67
+ Thumbs.db
68
+
69
+ # Claude Code local settings (machine-specific; .claude/CLAUDE.md IS tracked)
70
+ .claude/settings.local.json
71
+ .claude/scheduled_tasks.lock
@@ -0,0 +1,22 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-toml
9
+ - id: check-added-large-files
10
+ args: ["--maxkb=1024"]
11
+ - id: check-merge-conflict
12
+ - id: mixed-line-ending
13
+ args: ["--fix=lf"]
14
+
15
+ - repo: https://github.com/astral-sh/ruff-pre-commit
16
+ rev: v0.16.0
17
+ hooks:
18
+ - id: ruff
19
+ args: ["--fix"]
20
+ files: ^(src|tests)/
21
+ - id: ruff-format
22
+ files: ^(src|tests)/
@@ -0,0 +1,212 @@
1
+ # Contributing to minilake
2
+
3
+ Thanks for wanting to contribute. minilake emulates the Databricks REST API for a single developer running it locally — real SQL via DuckDB, real Delta Lake, real Job execution, no cloud, no fake auth. Each API group is one service module plus one models module; adding a new endpoint or fixing a bug should take minutes, not hours.
4
+
5
+ ## Project Structure
6
+
7
+ ```
8
+ minilake/
9
+ ├── src/minilake/
10
+ │ ├── app.py # FastAPI app factory, lifespan (DuckDB pool, persistence)
11
+ │ ├── admin.py # /_minilake/health, /ready, /reset, /services
12
+ │ ├── cli.py # `minilake` entry point
13
+ │ ├── config.py # Settings (env vars)
14
+ │ ├── errors.py # DatabricksError -> {error_code, message}
15
+ │ ├── duckdb_pool.py # Per-catalog ATTACH, per-warehouse connections
16
+ │ ├── docker_executor.py # Sibling-container (or subprocess) real Job execution
17
+ │ ├── persistence.py # MINILAKE_PERSIST JSON snapshot save/load
18
+ │ ├── models/
19
+ │ │ ├── unity_catalog.py, jobs.py, sql.py, secrets.py, clusters.py, ...
20
+ │ └── services/
21
+ │ ├── __init__.py # SERVICE_REGISTRY (name -> module path)
22
+ │ ├── unity_catalog.py, jobs.py, sql_statements.py, clusters.py, ...
23
+ ├── tests/
24
+ │ ├── conftest.py # minilake_server, workspace_client, reset_state fixtures
25
+ │ ├── test_<service>.py # one file per service, real databricks-sdk client
26
+ │ └── unity_catalog/ # sub-package for UC's larger surface area
27
+ ├── .github/workflows/ # ci.yml (lint + tests), release.yml (tag -> GHCR + Release)
28
+ ├── Dockerfile, docker-compose*.yml
29
+ └── FEATURES.md # endpoint-by-endpoint status, source of truth for scope
30
+ ```
31
+
32
+ ---
33
+
34
+ ## For infrastructure changes (Dockerfiles, CI/CD workflows, pyproject, dependencies), open an issue first. PRs containing such changes without a prior issue will be rejected.
35
+
36
+ ## For New API Groups — Open an Issue First
37
+
38
+ > **This section applies only when you are adding a brand-new Databricks API group** (a new module under `src/minilake/services/`).
39
+
40
+ **Before writing any code for a new API group, open a GitHub issue.** Use the `enhancement` label and describe:
41
+
42
+ 1. **Which Databricks API group** (e.g. `Repos`, `Model Registry`, `Query History`) and its base path (e.g. `/api/2.0/repos`).
43
+ 2. **Which operations** you actually need — not the full API surface. minilake favors the operations real `databricks-sdk`/Terraform-provider users actually hit over wire-format completeness for every action.
44
+ 3. **A real use case** — what SDK call, Terraform resource, or CI workflow drove the need. "I want full parity with Databricks" is not a use case.
45
+ 4. **Real vs. state-machine vs. stub** — per this project's "fail loudly, don't fake it" philosophy (see `.claude/CLAUDE.md`), be explicit about what will actually execute for real (like SQL/Delta/Jobs do today) versus what will be metadata-only. It's fine to ship a real state machine with no backing compute (like Clusters); it's not fine to ship 20 endpoints that silently return empty/fake data with no indication.
46
+ 5. **Scope boundaries** — what's explicitly out for the first PR.
47
+
48
+ A maintainer will confirm the scope and point you at the right pattern (synchronous DuckDB-backed, real-file-backed, or state-machine) before you write code. This avoids large PRs that get rejected for scope drift or for faking behavior the project deliberately avoids.
49
+
50
+ **PRs that add a new API group without a corresponding scoped issue will be closed and the contributor asked to open one.**
51
+
52
+ ---
53
+
54
+ ## Adding a New API Group
55
+
56
+ Every service follows the same pattern (see `.claude/CLAUDE.md` for the authoritative version of this checklist):
57
+
58
+ ### 1. Create `src/minilake/models/myservice.py`
59
+
60
+ Pydantic request/response models only — no business logic here.
61
+
62
+ ```python
63
+ from pydantic import BaseModel
64
+
65
+
66
+ class CreateThingRequest(BaseModel):
67
+ name: str
68
+
69
+
70
+ class ThingInfo(BaseModel):
71
+ name: str
72
+ created_at: int
73
+ ```
74
+
75
+ ### 2. Create `src/minilake/services/myservice.py`
76
+
77
+ ```python
78
+ """MyService API endpoints."""
79
+
80
+ import time
81
+ from typing import Any, Dict
82
+
83
+ from fastapi import APIRouter
84
+
85
+ from minilake.errors import DatabricksError
86
+ from minilake.models.myservice import CreateThingRequest, ThingInfo
87
+
88
+ router = APIRouter(prefix="/api/2.0/myservice", tags=["myservice"])
89
+
90
+ _state: Dict[str, Any] = {"things": {}}
91
+
92
+
93
+ @router.post("/things", response_model=ThingInfo)
94
+ async def create_thing(req: CreateThingRequest) -> ThingInfo:
95
+ if req.name in _state["things"]:
96
+ raise DatabricksError(error_code="ALREADY_EXISTS", message="...", status_code=400)
97
+ thing = {"name": req.name, "created_at": int(time.time() * 1000)}
98
+ _state["things"][req.name] = thing
99
+ return ThingInfo(**thing)
100
+
101
+
102
+ # ============================================================================
103
+ # State Management
104
+ # ============================================================================
105
+
106
+
107
+ def get_state() -> Dict[str, Any]:
108
+ return _state.copy()
109
+
110
+
111
+ def restore_state(data: Dict[str, Any]) -> None:
112
+ global _state
113
+ _state.update(data)
114
+
115
+
116
+ async def reset() -> None:
117
+ global _state
118
+ _state = {"things": {}}
119
+ ```
120
+
121
+ Every service module **must** export `router`, `get_state()`, `restore_state()`, `reset()`, and **must not** depend on global mutable state outside the module.
122
+
123
+ ### 3. Register in `src/minilake/services/__init__.py`
124
+
125
+ ```python
126
+ SERVICE_REGISTRY = {
127
+ # ... existing ...
128
+ "myservice": "minilake.services.myservice",
129
+ }
130
+ ```
131
+
132
+ ### 4. Write tests in `tests/test_myservice.py`
133
+
134
+ Tests **must** use the real `databricks-sdk` `WorkspaceClient`/`AccountClient` pointed at the local server — the SDK is the source of truth, not a mock:
135
+
136
+ ```python
137
+ import pytest
138
+ from databricks.sdk import WorkspaceClient
139
+
140
+
141
+ @pytest.mark.crud
142
+ def test_create_thing(workspace_client: WorkspaceClient):
143
+ thing = workspace_client.myservice.create_thing(name="test")
144
+ assert thing.name == "test"
145
+ ```
146
+
147
+ Use `@pytest.mark.serial` for tests that mutate workspace-wide state and can't run in parallel; `@pytest.mark.crud`/`workflow`/`error` otherwise.
148
+
149
+ ### 5. Update `FEATURES.md`
150
+
151
+ Add an entry under the right section (Fully Implemented / Not Implemented) with the endpoint list and status — this file is the single source of truth for what's actually built.
152
+
153
+ ---
154
+
155
+ ## Running Tests Locally
156
+
157
+ ```bash
158
+ # Full suite, real server, real databricks-sdk client
159
+ docker compose -f docker-compose.test.yml up --build --abort-on-container-exit
160
+
161
+ # Locally without Docker (starts minilake as a subprocess)
162
+ uv run pytest tests/ -v
163
+
164
+ # A single service
165
+ uv run pytest tests/test_myservice.py -v
166
+
167
+ # With coverage
168
+ uv run pytest tests/ --cov=minilake --cov-report=html
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Code Conventions
174
+
175
+ (See `.claude/CLAUDE.md` for the full, authoritative set of project rules — this is a summary.)
176
+
177
+ - **Services own routes + state; models own shapes** — never define Pydantic models inside a service module.
178
+ - **`get_state()` / `restore_state()` / `reset()`** — every service exposes these three, called by `/_minilake/reset` and (if `MINILAKE_PERSIST=1`) by shutdown/startup snapshotting.
179
+ - **Real execution where feasible** — SQL against real DuckDB, files as real files, Jobs as real subprocesses/containers. Don't add a fake response where a real one is achievable.
180
+ - **Fail loudly on unsupported features** — return `501 {"error_code": "NOT_IMPLEMENTED", ...}` for out-of-scope APIs. Never silently accept and fake a response.
181
+ - **No real auth** — parse auth headers for routing only, never verify signatures. This is intentional (see [Known Gaps](README.md#known-gaps)), not a TODO.
182
+ - **Tests are real, not mocked** — every feature needs a `tests/test_<service>.py` using the real SDK client against a real running server.
183
+ - **Lint/format** — `ruff check` / `ruff format` via pre-commit (`uv run pre-commit install` after cloning; CI runs the same hooks).
184
+
185
+ ---
186
+
187
+ ## Pull Request Checklist
188
+
189
+ - [ ] Service module in `src/minilake/services/`, models in `src/minilake/models/`
190
+ - [ ] Registered in `SERVICE_REGISTRY` (`src/minilake/services/__init__.py`)
191
+ - [ ] `get_state()` / `restore_state()` / `reset()` implemented
192
+ - [ ] Tests added in `tests/test_<service>.py` using the real `databricks-sdk` client, and passing
193
+ - [ ] `uv run pre-commit run --all-files` passes (lint + format)
194
+ - [ ] `FEATURES.md` updated with the new endpoint list and status
195
+ - [ ] Full suite still green: `docker compose -f docker-compose.test.yml up --build --abort-on-container-exit`
196
+
197
+ ---
198
+
199
+ ## What We're Looking For
200
+
201
+ High-value contributions right now (see `FEATURES.md`'s Roadmap for the full picture):
202
+
203
+ - **Test coverage for existing modules** — `jobs.py`, `sql_statements.py`, and `unity_catalog.py` are covered mostly on happy paths; edge cases and error branches need more tests.
204
+ - **Secrets ACLs** (`secrets/acls/*`) — scope/secret CRUD is real, ACL endpoints don't exist yet.
205
+ - **DBT task / pipeline task execution** in Jobs.
206
+ - **Real Unity Catalog REST protocol for native Spark catalog resolution** — see FEATURES.md Roadmap Phase 7 for what this actually involves; it's a materially larger effort, discuss scope in an issue first.
207
+
208
+ ---
209
+
210
+ ## Questions?
211
+
212
+ Open a GitHub Discussion or file an issue with the `question` label.
@@ -0,0 +1,40 @@
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /opt/minilake
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ build-essential \
8
+ curl \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy project files
12
+ COPY pyproject.toml pyproject.toml
13
+ COPY src/ src/
14
+ COPY README.md README.md
15
+
16
+ # Install minilake with the MCP extra. Baked into the image so MINILAKE_MCP=1 is all that's
17
+ # needed to turn the MCP server on; the extra stays optional for PyPI installs.
18
+ RUN pip install --no-cache-dir -e ".[mcp]"
19
+
20
+ # Create data directory
21
+ RUN mkdir -p /data
22
+
23
+ # Expose ports (HTTP + HTTPS)
24
+ EXPOSE 8000 8443
25
+
26
+ # Set environment variables
27
+ ENV PYTHONUNBUFFERED=1
28
+ ENV MINILAKE_DATA_DIR=/data
29
+ ENV MINILAKE_HOST=0.0.0.0
30
+ ENV MINILAKE_PORT=8000
31
+ # Native HTTPS is opt-in: set MINILAKE_TLS=1 to also serve TLS on :8443 (an
32
+ # auto-generated self-signed cert lands under /data/certs). To bring your own
33
+ # cert, set MINILAKE_SSL_CERTFILE / MINILAKE_SSL_KEYFILE.
34
+
35
+ # Health check
36
+ HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=3 \
37
+ CMD curl -f http://localhost:8000/_minilake/health || exit 1
38
+
39
+ # Run minilake server
40
+ CMD ["minilake", "--host", "0.0.0.0", "--port", "8000"]
@@ -0,0 +1,22 @@
1
+ FROM jupyter/pyspark-notebook:spark-3.5.0
2
+
3
+ USER root
4
+
5
+ # Delta Lake, matching this image's bundled Spark 3.5.0.
6
+ RUN pip install --no-cache-dir delta-spark==3.1.0 databricks-sdk
7
+
8
+ # Pre-resolve and cache the Delta Lake jars at build time so the first cell a
9
+ # user runs doesn't need network access / Maven resolution.
10
+ RUN python3 -c "\
11
+ from delta import configure_spark_with_delta_pip; \
12
+ from pyspark.sql import SparkSession; \
13
+ builder = SparkSession.builder.appName('warmup') \
14
+ .config('spark.sql.extensions', 'io.delta.sql.DeltaSparkSessionExtension') \
15
+ .config('spark.sql.catalog.spark_catalog', 'org.apache.spark.sql.delta.catalog.DeltaCatalog'); \
16
+ spark = configure_spark_with_delta_pip(builder).getOrCreate(); \
17
+ spark.stop()"
18
+
19
+ COPY notebooks/minilake_delta_quickstart.ipynb /home/${NB_USER}/work/minilake_delta_quickstart.ipynb
20
+ RUN chown ${NB_UID}:${NB_GID} /home/${NB_USER}/work/minilake_delta_quickstart.ipynb
21
+
22
+ USER ${NB_UID}
@@ -0,0 +1,41 @@
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /opt/minilake
4
+
5
+ # Install system dependencies + uv
6
+ RUN apt-get update && apt-get install -y \
7
+ build-essential \
8
+ curl \
9
+ && rm -rf /var/lib/apt/lists/* && \
10
+ pip install --no-cache-dir uv
11
+
12
+ # Copy project files
13
+ COPY pyproject.toml pyproject.toml
14
+ COPY src/ src/
15
+ COPY tests/ tests/
16
+ COPY README.md README.md
17
+
18
+ # Install minilake + all dev dependencies
19
+ RUN uv pip install -e ".[mcp]" --python /usr/local/bin/python && \
20
+ uv pip install \
21
+ pytest>=8.0 \
22
+ pytest-xdist>=3.6 \
23
+ httpx>=0.27 \
24
+ databricks-sdk>=0.40 \
25
+ pytest-cov \
26
+ pytest-json-report \
27
+ pytest-asyncio \
28
+ deltalake>=0.19 \
29
+ pandas>=2.0 \
30
+ pyarrow>=14.0 \
31
+ --python /usr/local/bin/python
32
+
33
+ # Create data directory for tests
34
+ RUN mkdir -p /data
35
+
36
+ # Set test environment
37
+ ENV MINILAKE_DATA_DIR=/data
38
+ ENV PYTHONUNBUFFERED=1
39
+
40
+ # Run tests
41
+ CMD ["pytest", "tests/", "-v", "--cov=minilake", "--cov-report=html", "--cov-report=term-missing", "--tb=short"]