semblance-databricks 0.1.0__py3-none-any.whl

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 (42) hide show
  1. semblance_databricks/__init__.py +19 -0
  2. semblance_databricks/app.py +104 -0
  3. semblance_databricks/auth.py +145 -0
  4. semblance_databricks/cli.py +112 -0
  5. semblance_databricks/compatibility.py +30 -0
  6. semblance_databricks/compatibility.yaml +269 -0
  7. semblance_databricks/config.py +52 -0
  8. semblance_databricks/errors.py +72 -0
  9. semblance_databricks/fixtures/__init__.py +5 -0
  10. semblance_databricks/fixtures/defaults/__init__.py +0 -0
  11. semblance_databricks/fixtures/defaults/acme.yaml +47 -0
  12. semblance_databricks/fixtures/loaders.py +196 -0
  13. semblance_databricks/http.py +34 -0
  14. semblance_databricks/ids.py +88 -0
  15. semblance_databricks/models/__init__.py +1 -0
  16. semblance_databricks/pagination.py +48 -0
  17. semblance_databricks/py.typed +0 -0
  18. semblance_databricks/registry.py +29 -0
  19. semblance_databricks/services/__init__.py +1 -0
  20. semblance_databricks/services/clusters/__init__.py +3 -0
  21. semblance_databricks/services/clusters/routes.py +191 -0
  22. semblance_databricks/services/dbfs/__init__.py +3 -0
  23. semblance_databricks/services/dbfs/routes.py +126 -0
  24. semblance_databricks/services/dbsql/__init__.py +3 -0
  25. semblance_databricks/services/dbsql/routes.py +163 -0
  26. semblance_databricks/services/deps.py +37 -0
  27. semblance_databricks/services/jobs/__init__.py +3 -0
  28. semblance_databricks/services/jobs/routes.py +168 -0
  29. semblance_databricks/services/permissions/__init__.py +5 -0
  30. semblance_databricks/services/permissions/routes.py +50 -0
  31. semblance_databricks/services/secrets/__init__.py +3 -0
  32. semblance_databricks/services/secrets/routes.py +53 -0
  33. semblance_databricks/services/workspace/__init__.py +3 -0
  34. semblance_databricks/services/workspace/routes.py +39 -0
  35. semblance_databricks/state.py +253 -0
  36. semblance_databricks/testing.py +66 -0
  37. semblance_databricks-0.1.0.dist-info/METADATA +126 -0
  38. semblance_databricks-0.1.0.dist-info/RECORD +42 -0
  39. semblance_databricks-0.1.0.dist-info/WHEEL +5 -0
  40. semblance_databricks-0.1.0.dist-info/entry_points.txt +2 -0
  41. semblance_databricks-0.1.0.dist-info/licenses/LICENSE.md +21 -0
  42. semblance_databricks-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,19 @@
1
+ """
2
+ Unofficial local simulation of selected Databricks workspace REST operations.
3
+
4
+ Not affiliated with, endorsed by, or equivalent to Databricks.
5
+ """
6
+
7
+ from semblance_databricks.app import DatabricksMock
8
+ from semblance_databricks.config import DatabricksMockConfig, TokenGrant
9
+ from semblance_databricks.fixtures.loaders import load_bundled_fixture
10
+ from semblance_databricks.testing import DatabricksMockContext, databricks_test_client
11
+
12
+ __all__ = [
13
+ "DatabricksMock",
14
+ "DatabricksMockConfig",
15
+ "DatabricksMockContext",
16
+ "TokenGrant",
17
+ "databricks_test_client",
18
+ "load_bundled_fixture",
19
+ ]
@@ -0,0 +1,104 @@
1
+ """DatabricksMock factory and ASGI construction."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import random
6
+ from collections.abc import Callable
7
+ from importlib.metadata import PackageNotFoundError
8
+ from importlib.metadata import version as pkg_version
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ from fastapi import FastAPI
13
+
14
+ from semblance_databricks.auth import DatabricksMiddleware
15
+ from semblance_databricks.compatibility import manifest_json
16
+ from semblance_databricks.config import DatabricksMockConfig
17
+ from semblance_databricks.errors import register_exception_handlers
18
+ from semblance_databricks.fixtures.loaders import (
19
+ apply_fixture,
20
+ bundled_acme_path,
21
+ load_fixture_file,
22
+ )
23
+ from semblance_databricks.ids import PageTokenCodec, token_secret
24
+ from semblance_databricks.services.clusters import create_clusters_router
25
+ from semblance_databricks.services.dbfs import create_dbfs_router
26
+ from semblance_databricks.services.dbsql import create_dbsql_router
27
+ from semblance_databricks.services.jobs import create_jobs_router
28
+ from semblance_databricks.services.permissions import create_permissions_router
29
+ from semblance_databricks.services.secrets import create_secrets_router
30
+ from semblance_databricks.services.workspace import create_workspace_router
31
+ from semblance_databricks.state import DatabricksState
32
+
33
+ _BUNDLED_FIXTURES = {"acme": bundled_acme_path}
34
+
35
+
36
+ def _distribution_version() -> str:
37
+ try:
38
+ return pkg_version("semblance-databricks")
39
+ except PackageNotFoundError:
40
+ return "0.1.0"
41
+
42
+
43
+ class DatabricksMock:
44
+ """Fixture-backed local simulation of selected Databricks REST operations."""
45
+
46
+ def __init__(self, config: DatabricksMockConfig | None = None) -> None:
47
+ self.config = config or DatabricksMockConfig()
48
+ self.state = DatabricksState(seed=self.config.seed)
49
+ self.page_token_codec = PageTokenCodec(token_secret(self.config.seed))
50
+ self._rng = random.Random(self.config.seed)
51
+
52
+ def load_fixture(self, path: str | Path) -> DatabricksMock:
53
+ self.state.clear()
54
+ doc = load_fixture_file(path)
55
+ apply_fixture(doc, self.state)
56
+ return self
57
+
58
+ def load_bundled_fixture(self, name: str = "acme") -> DatabricksMock:
59
+ """Load a fixture shipped with the package (currently ``acme``)."""
60
+ loader = _BUNDLED_FIXTURES.get(name)
61
+ if loader is None:
62
+ known = ", ".join(sorted(_BUNDLED_FIXTURES))
63
+ raise ValueError(
64
+ f"unknown bundled fixture {name!r}; expected one of: {known}"
65
+ )
66
+ return self.load_fixture(loader())
67
+
68
+ def tick(self) -> None:
69
+ """Advance virtual-clock cluster and run state machines."""
70
+ self.state.tick()
71
+
72
+ def register_statement(self, key: str, fn: Callable[..., Any]) -> None:
73
+ """Register an allow-listed callback keyed by SQL text or warehouse id."""
74
+ self.state.statement_callbacks[key] = fn
75
+
76
+ def as_fastapi(self) -> FastAPI:
77
+ app = FastAPI(
78
+ title="semblance-databricks",
79
+ description=(
80
+ "Unofficial local simulation of selected Databricks workspace "
81
+ "REST operations. Not affiliated with Databricks."
82
+ ),
83
+ version=_distribution_version(),
84
+ )
85
+ app.state.databricks_mock = self
86
+ register_exception_handlers(app)
87
+ app.add_middleware(
88
+ DatabricksMiddleware,
89
+ config=self.config,
90
+ rng=self._rng,
91
+ )
92
+ app.include_router(create_clusters_router())
93
+ app.include_router(create_jobs_router())
94
+ app.include_router(create_workspace_router())
95
+ app.include_router(create_dbsql_router())
96
+ app.include_router(create_secrets_router())
97
+ app.include_router(create_dbfs_router())
98
+ app.include_router(create_permissions_router())
99
+
100
+ @app.get("/.well-known/semblance-databricks-compat.json")
101
+ def compatibility() -> dict[str, Any]:
102
+ return manifest_json()
103
+
104
+ return app
@@ -0,0 +1,145 @@
1
+ """Auth, request-id, latency, error injection, and rate-limit middleware."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import random
7
+ import time
8
+ from collections import defaultdict
9
+ from collections.abc import Callable
10
+ from threading import Lock
11
+ from typing import Any
12
+
13
+ from starlette.middleware.base import BaseHTTPMiddleware
14
+ from starlette.requests import Request
15
+ from starlette.responses import JSONResponse, Response
16
+
17
+ from semblance_databricks.config import DatabricksMockConfig
18
+ from semblance_databricks.errors import databricks_error_body
19
+
20
+ REQUEST_ID_HEADER = "x-databricks-request-id"
21
+ ORG_ID_HEADER = "x-databricks-org-id"
22
+
23
+
24
+ class _SlidingWindow:
25
+ def __init__(self) -> None:
26
+ self._timestamps: dict[tuple[str, str], list[float]] = defaultdict(list)
27
+ self._lock = Lock()
28
+
29
+ def allow(self, path: str, method: str, limit: float) -> bool:
30
+ if limit <= 0:
31
+ return True
32
+ now = time.monotonic()
33
+ key = (path, method)
34
+ with self._lock:
35
+ ts_list = self._timestamps[key]
36
+ ts_list[:] = [t for t in ts_list if now - t < 1.0]
37
+ if len(ts_list) >= limit:
38
+ return False
39
+ ts_list.append(now)
40
+ return True
41
+
42
+
43
+ def _bearer_token(header: str | None) -> str | None:
44
+ if header is None or header == "":
45
+ return None
46
+ parts = header.split(None, 1)
47
+ if len(parts) != 2 or parts[0].lower() != "bearer":
48
+ raise ValueError("malformed")
49
+ token = parts[1].strip()
50
+ if not token:
51
+ raise ValueError("empty")
52
+ return token
53
+
54
+
55
+ class DatabricksMiddleware(BaseHTTPMiddleware):
56
+ def __init__(
57
+ self,
58
+ app: Any,
59
+ config: DatabricksMockConfig,
60
+ rng: random.Random,
61
+ ) -> None:
62
+ super().__init__(app)
63
+ self._config = config
64
+ self._rng = rng
65
+ self._limiter = _SlidingWindow()
66
+ self._req_n = 0
67
+
68
+ async def dispatch(
69
+ self, request: Request, call_next: Callable[[Request], Any]
70
+ ) -> Response:
71
+ incoming = request.headers.get(REQUEST_ID_HEADER)
72
+ self._req_n += 1
73
+ request_id = incoming if incoming else f"req-{self._config.seed}-{self._req_n}"
74
+ request.state.request_id = request_id
75
+
76
+ if self._config.rate_limit is not None:
77
+ if not self._limiter.allow(
78
+ request.url.path, request.method, self._config.rate_limit
79
+ ):
80
+ response = JSONResponse(
81
+ status_code=429,
82
+ content=databricks_error_body(
83
+ "REQUEST_LIMIT_EXCEEDED", "Rate limit exceeded"
84
+ ),
85
+ )
86
+ self._stamp(response, request_id)
87
+ return response
88
+
89
+ auth_error = self._check_auth(request)
90
+ if auth_error is not None:
91
+ self._stamp(auth_error, request_id)
92
+ return auth_error
93
+
94
+ if self._config.latency_ms or self._config.jitter_ms:
95
+ delay = self._config.latency_ms / 1000.0
96
+ if self._config.jitter_ms:
97
+ delay += self._rng.uniform(0, self._config.jitter_ms) / 1000.0
98
+ if delay > 0:
99
+ await asyncio.sleep(delay)
100
+
101
+ if self._config.error_rate > 0 and self._rng.random() < self._config.error_rate:
102
+ codes = self._config.error_codes or [500]
103
+ status = self._rng.choice(codes)
104
+ response = JSONResponse(
105
+ status_code=status,
106
+ content=databricks_error_body("INTERNAL_ERROR", "Injected error"),
107
+ )
108
+ self._stamp(response, request_id)
109
+ return response
110
+
111
+ response = await call_next(request)
112
+ self._stamp(response, request_id)
113
+ return response # type: ignore[no-any-return]
114
+
115
+ def _stamp(self, response: Response, request_id: str) -> None:
116
+ response.headers[REQUEST_ID_HEADER] = request_id
117
+ if self._config.org_id:
118
+ response.headers[ORG_ID_HEADER] = self._config.org_id
119
+
120
+ def _check_auth(self, request: Request) -> JSONResponse | None:
121
+ mode = self._config.auth
122
+ if mode == "disabled":
123
+ return None
124
+ header = request.headers.get("authorization")
125
+ try:
126
+ token = _bearer_token(header)
127
+ except ValueError:
128
+ return JSONResponse(
129
+ status_code=401,
130
+ content=databricks_error_body("UNAUTHENTICATED", "Invalid credentials"),
131
+ )
132
+ if mode == "optional":
133
+ return None
134
+ if token is None:
135
+ return JSONResponse(
136
+ status_code=401,
137
+ content=databricks_error_body("UNAUTHENTICATED", "Missing credentials"),
138
+ )
139
+ allowed = {g.token for g in self._config.tokens}
140
+ if token not in allowed:
141
+ return JSONResponse(
142
+ status_code=401,
143
+ content=databricks_error_body("UNAUTHENTICATED", "Invalid credentials"),
144
+ )
145
+ return None
@@ -0,0 +1,112 @@
1
+ """CLI: serve, validate, fixture init, operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import os
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ from semblance_databricks.app import DatabricksMock
11
+ from semblance_databricks.config import DatabricksMockConfig
12
+ from semblance_databricks.fixtures.loaders import bundled_acme_path, load_fixture_file
13
+ from semblance_databricks.registry import registered_operations
14
+
15
+
16
+ def cmd_serve(args: argparse.Namespace) -> None:
17
+ seed = (
18
+ args.seed
19
+ if args.seed is not None
20
+ else int(os.environ.get("SEMBLANCE_DATABRICKS_SEED", "42"))
21
+ )
22
+ host = os.environ.get("SEMBLANCE_DATABRICKS_HOST", args.host)
23
+ config = DatabricksMockConfig(seed=seed, auth=args.auth)
24
+ mock = DatabricksMock(config)
25
+ mock.load_fixture(args.fixture or bundled_acme_path())
26
+ app = mock.as_fastapi()
27
+ try:
28
+ import uvicorn
29
+ except ImportError as exc:
30
+ raise SystemExit(
31
+ "uvicorn not found. Install semblance (pulls uvicorn)."
32
+ ) from exc
33
+ uvicorn.run(app, host=host, port=args.port)
34
+
35
+
36
+ def cmd_validate(args: argparse.Namespace) -> None:
37
+ try:
38
+ load_fixture_file(args.fixture)
39
+ except Exception as exc:
40
+ raise SystemExit(f"Invalid fixture: {exc}") from exc
41
+ print("OK")
42
+
43
+
44
+ def cmd_fixture_init(args: argparse.Namespace) -> None:
45
+ dest = Path(args.output)
46
+ if dest.exists() and not args.force:
47
+ raise SystemExit(f"{dest} already exists (use --force to overwrite)")
48
+ dest.write_text(bundled_acme_path().read_text(encoding="utf-8"), encoding="utf-8")
49
+ print(f"Wrote {dest}")
50
+
51
+
52
+ def cmd_operations(_args: argparse.Namespace) -> None:
53
+ rows = registered_operations()
54
+ width = max((len(op.operation_id) for op in rows), default=8)
55
+ print(f"{'operation':<{width}} {'level':<16} method path")
56
+ for op in rows:
57
+ print(
58
+ f"{op.operation_id:<{width}} {op.support_level:<16} "
59
+ f"{op.method:<6} {op.path}"
60
+ )
61
+
62
+
63
+ def build_parser() -> argparse.ArgumentParser:
64
+ parser = argparse.ArgumentParser(
65
+ prog="semblance-databricks",
66
+ description=(
67
+ "Unofficial local Databricks workspace REST mock. "
68
+ "Not affiliated with Databricks."
69
+ ),
70
+ )
71
+ sub = parser.add_subparsers(dest="command", required=True)
72
+
73
+ serve = sub.add_parser("serve", help="Run a local mock server")
74
+ serve.add_argument(
75
+ "--fixture",
76
+ default=None,
77
+ help="YAML or JSON fixture path (default: bundled acme example)",
78
+ )
79
+ serve.add_argument("--host", default="127.0.0.1")
80
+ serve.add_argument("--port", type=int, default=8766)
81
+ serve.add_argument("--seed", type=int, default=None)
82
+ serve.add_argument(
83
+ "--auth",
84
+ default="optional",
85
+ choices=["disabled", "optional", "strict"],
86
+ )
87
+ serve.set_defaults(func=cmd_serve)
88
+
89
+ validate = sub.add_parser("validate", help="Validate a fixture without serving")
90
+ validate.add_argument("fixture")
91
+ validate.set_defaults(func=cmd_validate)
92
+
93
+ init = sub.add_parser("fixture", help="Fixture helpers")
94
+ init_sub = init.add_subparsers(dest="fixture_command", required=True)
95
+ init_cmd = init_sub.add_parser("init", help="Write the bundled example fixture")
96
+ init_cmd.add_argument("--output", required=True)
97
+ init_cmd.add_argument("--force", action="store_true")
98
+ init_cmd.set_defaults(func=cmd_fixture_init)
99
+
100
+ ops = sub.add_parser("operations", help="Print the compatibility table")
101
+ ops.set_defaults(func=cmd_operations)
102
+ return parser
103
+
104
+
105
+ def main(argv: list[str] | None = None) -> None:
106
+ parser = build_parser()
107
+ args = parser.parse_args(argv)
108
+ args.func(args)
109
+
110
+
111
+ if __name__ == "__main__":
112
+ main(sys.argv[1:])
@@ -0,0 +1,30 @@
1
+ """Load and publish the per-operation compatibility manifest."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from functools import lru_cache
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import yaml
10
+
11
+ _MANIFEST_PATH = Path(__file__).resolve().parent / "compatibility.yaml"
12
+
13
+
14
+ @lru_cache(maxsize=1)
15
+ def load_manifest() -> dict[str, Any]:
16
+ data = yaml.safe_load(_MANIFEST_PATH.read_text(encoding="utf-8"))
17
+ if not isinstance(data, dict):
18
+ raise ValueError("compatibility.yaml must be a mapping")
19
+ return data
20
+
21
+
22
+ def manifest_json() -> dict[str, Any]:
23
+ return load_manifest()
24
+
25
+
26
+ def operations_table() -> list[dict[str, Any]]:
27
+ ops = load_manifest().get("operations", [])
28
+ if not isinstance(ops, list):
29
+ return []
30
+ return [op for op in ops if isinstance(op, dict)]
@@ -0,0 +1,269 @@
1
+ packageVersion: "0.1.0"
2
+ documentedAt: "2026-08-19"
3
+ source: "https://docs.databricks.com/api/workspace/"
4
+ operations:
5
+ - operationId: ListClusters
6
+ method: GET
7
+ path: /api/2.1/clusters/list
8
+ supportLevel: exact
9
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/list
10
+ tests:
11
+ - tests/contract/test_clusters.py::test_list_clusters
12
+ - operationId: GetCluster
13
+ method: GET
14
+ path: /api/2.1/clusters/get
15
+ supportLevel: exact
16
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/get
17
+ tests:
18
+ - tests/contract/test_clusters.py::test_get_cluster
19
+ - operationId: ListJobs
20
+ method: GET
21
+ path: /api/2.2/jobs/list
22
+ supportLevel: exact
23
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/list
24
+ tests:
25
+ - tests/contract/test_jobs.py::test_list_jobs
26
+ - operationId: GetJob
27
+ method: GET
28
+ path: /api/2.2/jobs/get
29
+ supportLevel: exact
30
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/get
31
+ tests:
32
+ - tests/contract/test_jobs.py::test_get_job
33
+ - operationId: GetRun
34
+ method: GET
35
+ path: /api/2.2/jobs/runs/get
36
+ supportLevel: exact
37
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/getrun
38
+ tests:
39
+ - tests/contract/test_runs.py::test_get_run
40
+ - operationId: GetStatus
41
+ method: GET
42
+ path: /api/2.0/workspace/get-status
43
+ supportLevel: exact
44
+ docsUrl: https://docs.databricks.com/api/workspace/workspace/getstatus
45
+ tests:
46
+ - tests/contract/test_workspace.py::test_get_status
47
+ - operationId: CurrentUserMe
48
+ method: GET
49
+ path: /api/2.0/preview/scim/v2/Me
50
+ supportLevel: representative
51
+ docsUrl: https://docs.databricks.com/api/workspace/currentuser/
52
+ tests:
53
+ - tests/contract/test_workspace.py::test_me
54
+ - operationId: CreateCluster
55
+ method: POST
56
+ path: /api/2.1/clusters/create
57
+ supportLevel: exact
58
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/create
59
+ tests:
60
+ - tests/contract/test_clusters.py::test_create_cluster_virtual_clock
61
+ - operationId: EditCluster
62
+ method: POST
63
+ path: /api/2.1/clusters/edit
64
+ supportLevel: representative
65
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/edit
66
+ tests:
67
+ - tests/contract/test_clusters.py::test_edit_cluster
68
+ - operationId: DeleteCluster
69
+ method: POST
70
+ path: /api/2.1/clusters/delete
71
+ supportLevel: exact
72
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/delete
73
+ tests:
74
+ - tests/contract/test_clusters.py::test_delete_cluster
75
+ - operationId: RestartCluster
76
+ method: POST
77
+ path: /api/2.1/clusters/restart
78
+ supportLevel: exact
79
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/restart
80
+ tests:
81
+ - tests/contract/test_clusters.py::test_restart_cluster
82
+ - operationId: PermanentDeleteCluster
83
+ method: POST
84
+ path: /api/2.1/clusters/permanent-delete
85
+ supportLevel: stub
86
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/permanentdelete
87
+ tests:
88
+ - tests/contract/test_unsupported.py::test_permanent_delete_strict_501
89
+ - operationId: CreateJob
90
+ method: POST
91
+ path: /api/2.2/jobs/create
92
+ supportLevel: exact
93
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/create
94
+ tests:
95
+ - tests/contract/test_jobs.py::test_create_job
96
+ - operationId: ResetJob
97
+ method: POST
98
+ path: /api/2.2/jobs/reset
99
+ supportLevel: representative
100
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/reset
101
+ tests:
102
+ - tests/contract/test_jobs.py::test_reset_job
103
+ - operationId: DeleteJob
104
+ method: POST
105
+ path: /api/2.2/jobs/delete
106
+ supportLevel: exact
107
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/delete
108
+ tests:
109
+ - tests/contract/test_jobs.py::test_delete_job
110
+ - operationId: SubmitRun
111
+ method: POST
112
+ path: /api/2.2/jobs/runs/submit
113
+ supportLevel: exact
114
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/submit
115
+ tests:
116
+ - tests/contract/test_runs.py::test_submit_and_cancel
117
+ - operationId: CancelRun
118
+ method: POST
119
+ path: /api/2.2/jobs/runs/cancel
120
+ supportLevel: exact
121
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/cancelrun
122
+ tests:
123
+ - tests/contract/test_runs.py::test_submit_and_cancel
124
+ - operationId: ListWarehouses
125
+ method: GET
126
+ path: /api/2.0/sql/warehouses
127
+ supportLevel: exact
128
+ docsUrl: https://docs.databricks.com/api/workspace/warehouses/list
129
+ tests:
130
+ - tests/contract/test_warehouses.py::test_list_warehouses
131
+ - operationId: GetWarehouse
132
+ method: GET
133
+ path: /api/2.0/sql/warehouses/{id}
134
+ supportLevel: exact
135
+ docsUrl: https://docs.databricks.com/api/workspace/warehouses/get
136
+ tests:
137
+ - tests/contract/test_warehouses.py::test_get_warehouse
138
+ - operationId: CreateWarehouse
139
+ method: POST
140
+ path: /api/2.0/sql/warehouses
141
+ supportLevel: representative
142
+ docsUrl: https://docs.databricks.com/api/workspace/warehouses/create
143
+ tests:
144
+ - tests/contract/test_warehouses.py::test_create_delete_warehouse
145
+ - operationId: DeleteWarehouse
146
+ method: DELETE
147
+ path: /api/2.0/sql/warehouses/{id}
148
+ supportLevel: representative
149
+ docsUrl: https://docs.databricks.com/api/workspace/warehouses/delete
150
+ tests:
151
+ - tests/contract/test_warehouses.py::test_create_delete_warehouse
152
+ - operationId: PutSecret
153
+ method: POST
154
+ path: /api/2.0/secrets/put
155
+ supportLevel: representative
156
+ docsUrl: https://docs.databricks.com/api/workspace/secrets/putsecret
157
+ tests:
158
+ - tests/contract/test_secrets.py::test_put_and_list_keys_only
159
+ - operationId: ListSecrets
160
+ method: GET
161
+ path: /api/2.0/secrets/list
162
+ supportLevel: exact
163
+ docsUrl: https://docs.databricks.com/api/workspace/secrets/listsecrets
164
+ tests:
165
+ - tests/contract/test_secrets.py::test_list_secret_keys
166
+ - operationId: ListSecretScopes
167
+ method: GET
168
+ path: /api/2.0/secrets/scopes/list
169
+ supportLevel: exact
170
+ docsUrl: https://docs.databricks.com/api/workspace/secrets/listscopes
171
+ tests:
172
+ - tests/contract/test_secrets.py::test_list_scopes
173
+ - operationId: InstallLibraries
174
+ method: POST
175
+ path: /api/2.0/libraries/install
176
+ supportLevel: representative
177
+ docsUrl: https://docs.databricks.com/api/workspace/libraries/installlibraries
178
+ tests:
179
+ - tests/contract/test_libraries.py::test_install_uninstall
180
+ - operationId: UninstallLibraries
181
+ method: POST
182
+ path: /api/2.0/libraries/uninstall
183
+ supportLevel: representative
184
+ docsUrl: https://docs.databricks.com/api/workspace/libraries/uninstalllibraries
185
+ tests:
186
+ - tests/contract/test_libraries.py::test_install_uninstall
187
+ - operationId: GetRunOutput
188
+ method: GET
189
+ path: /api/2.2/jobs/runs/get-output
190
+ supportLevel: representative
191
+ docsUrl: https://docs.databricks.com/api/workspace/jobs/getrunoutput
192
+ tests:
193
+ - tests/contract/test_runs.py::test_get_output
194
+ - operationId: ListClusterEvents
195
+ method: POST
196
+ path: /api/2.1/clusters/events
197
+ supportLevel: representative
198
+ docsUrl: https://docs.databricks.com/api/workspace/clusters/events
199
+ tests:
200
+ - tests/contract/test_events.py::test_cluster_events
201
+ - operationId: ListDbfs
202
+ method: GET
203
+ path: /api/2.0/dbfs/list
204
+ supportLevel: representative
205
+ docsUrl: https://docs.databricks.com/api/workspace/dbfs/list
206
+ tests:
207
+ - tests/contract/test_dbfs.py::test_list_dbfs
208
+ - operationId: ReadDbfs
209
+ method: GET
210
+ path: /api/2.0/dbfs/read
211
+ supportLevel: representative
212
+ docsUrl: https://docs.databricks.com/api/workspace/dbfs/read
213
+ tests:
214
+ - tests/contract/test_dbfs.py::test_read_dbfs
215
+ - operationId: AddBlock
216
+ method: POST
217
+ path: /api/2.0/dbfs/add-block
218
+ supportLevel: stub
219
+ docsUrl: https://docs.databricks.com/api/workspace/dbfs/addblock
220
+ tests:
221
+ - tests/contract/test_unsupported.py::test_add_block_strict_501
222
+ - operationId: GetPermissions
223
+ method: GET
224
+ path: /api/2.0/permissions/{object_type}/{object_id}
225
+ supportLevel: representative
226
+ docsUrl: https://docs.databricks.com/api/workspace/permissions/
227
+ tests:
228
+ - tests/contract/test_permissions.py::test_get_permissions
229
+ - operationId: UpdatePermissions
230
+ method: PATCH
231
+ path: /api/2.0/permissions/{object_type}/{object_id}
232
+ supportLevel: representative
233
+ docsUrl: https://docs.databricks.com/api/workspace/permissions/
234
+ tests:
235
+ - tests/contract/test_permissions.py::test_patch_permissions
236
+ - operationId: ExecuteStatement
237
+ method: POST
238
+ path: /api/2.0/sql/statements
239
+ supportLevel: representative
240
+ docsUrl: https://docs.databricks.com/api/workspace/statementexecution/execute
241
+ tests:
242
+ - tests/contract/test_sql.py::test_execute_statement
243
+ - operationId: GetStatement
244
+ method: GET
245
+ path: /api/2.0/sql/statements/{statement_id}
246
+ supportLevel: representative
247
+ docsUrl: https://docs.databricks.com/api/workspace/statementexecution/getstatement
248
+ tests:
249
+ - tests/contract/test_sql.py::test_get_statement
250
+ - operationId: ListJobs21
251
+ method: GET
252
+ path: /api/2.1/jobs/list
253
+ supportLevel: representative
254
+ notes: Jobs 2.1 alias of 2.2
255
+ tests:
256
+ - tests/contract/test_jobs.py::test_jobs_21_alias
257
+ - operationId: PutDbfs
258
+ method: POST
259
+ path: /api/2.0/dbfs/put
260
+ supportLevel: representative
261
+ docsUrl: https://docs.databricks.com/api/workspace/dbfs/put
262
+ tests:
263
+ - tests/contract/test_dbfs.py::test_put_and_read_base64
264
+ - operationId: Jobs20Unsupported
265
+ method: GET
266
+ path: /api/2.0/jobs/list
267
+ supportLevel: unsupported
268
+ tests:
269
+ - tests/contract/test_unsupported.py::test_unknown_path_404