Skip to main content

databricks-isv-python-sqlalchemy

Comprehensive SQLAlchemy + Databricks patterns: PAT/M2M/U2M authentication, User-Agent telemetry, connection URL format, error handling, and retry logic. Use when building or testing Python integrations using databricks-sqlalchemy dialect.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
databricks-solutions/partner-ai-dev-kit
آخر نشاط في المصدر
١٥ أبريل ٢٠٢٦ في ٠٠:٣٦
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
2 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
databricks-isv-python-sqlalchemy
description
Comprehensive SQLAlchemy + Databricks patterns: PAT/M2M/U2M authentication, User-Agent telemetry, connection URL format, error handling, and retry logic. Use when building or testing Python integrations using databricks-sqlalchemy dialect.
<!-- skill-version: 1.0.0 --> # Python SQLAlchemy + Databricks (ISV) Use this skill when implementing SQLAlchemy with the Databricks dialect (`databricks-sqlalchemy`) for partner integrations. SQLAlchemy provides ORM capabilities and SQL abstraction on top of the `databricks-sql-connector` driver. ## PWAF Documentation Links - [Partner Architecture Overview](https://databrickslabs.github.io/partner-architecture/) - [Access & Authentication](https://databrickslabs.github.io/partner-architecture/isv-partners/lakehouse-patterns/access-auth/) - [OAuth M2M](https://databrickslabs.github.io/partner-architecture/isv-partners/lakehouse-patterns/access-auth/oauth-m2m) - [OAuth U2M](https://databrickslabs.github.io/partner-architecture/isv-partners/lakehouse-patterns/access-auth/oauth-u2m) - [Telemetry Attribution](https://databrickslabs.github.io/partner-architecture/isv-partners/lakehouse-patterns/access-auth/telemetry) ## Packages ```bash pip install databricks-sqlalchemy databricks-sql-connector sqlalchemy databricks-sdk requests ``` - `databricks-sqlalchemy`: SQLAlchemy dialect (registers `databricks://` URL scheme) - `databricks-sql-connector`: Underlying SQL driver - `sqlalchemy` 2.x: ORM and SQL toolkit - `databricks-sdk`: OAuth M2M token acquisition - `requests`: PKCE token exchange (U2M custom OAuth app) ## Authentication Decision Guide ``` ISV Integration Authentication Selection: 1. Is this for automated/unattended workloads (CI, jobs, services)? → OAuth M2M (Client Credentials) – RECOMMENDED 2. Is this for user-interactive flows (web app, desktop app)? → OAuth U2M with Custom OAuth App (PKCE) – RECOMMENDED 3. Is this for quick testing/development only? → PAT (Personal Access Token) – LIMITED USE 4. Is the OAuth token obtained externally (mobile app, web frontend)? → OAuth U2M Token-Env (pass pre-obtained token) ``` ## Authentication Comparison | Auth Type | Use Case | Token Lifetime | Refresh | PWAF Status | |-----------|----------|---------------|---------|-------------| | PAT | Testing/development | Configurable (90d default) | Manual regeneration | Limited | | OAuth M2M | Production, automated | 1 hour | Re-authenticate via SDK | Recommended | | OAuth U2M PKCE | User-interactive apps | 1 hour | Use refresh_token | Recommended | | OAuth U2M Token-Env | Headless/CI | 1 hour | External refresh | Supported | ## CLIENT_ID Distinction (CRITICAL) ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ DATABRICKS_CLIENT_ID vs DATABRICKS_U2M_CLIENT_ID │ ├─────────────────────────────────────────────────────────────────────────────┤ │ DATABRICKS_CLIENT_ID: │ │ - Service Principal UUID for OAuth M2M (machine-to-machine) │ │ - Created in: Workspace → Settings → Identity and access → Service │ │ principals │ │ - Used with: DATABRICKS_CLIENT_SECRET │ │ │ │ DATABRICKS_U2M_CLIENT_ID: │ │ - Custom OAuth Application client ID for OAuth U2M (user-to-machine) │ │ - Created in: Account Console → Settings → App connections │ │ - Used with: DATABRICKS_U2M_CLIENT_SECRET (if confidential app) │ │ │ │ NEVER mix these – they serve completely different authentication flows. │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ## Token Lifetime Summary | Token Type | Lifetime | Refresh Strategy | |------------|----------|-----------------| | PAT | Configurable (default 90 days) | Manual regeneration via workspace | | OAuth M2M access_token | 1 hour | Re-call `Config.authenticate()` | | OAuth U2M access_token | 1 hour | Use refresh_token or re-authenticate | | OAuth U2M refresh_token | Up to 90 days | Request `offline_access` scope | ## User-Agent (Required for PWAF) Format: `<isv-name>_<product-name>/<product-version>` ```python USER_AGENT = "YourCompany_YourProduct/1.0.0" engine = create_engine(url, connect_args={"user_agent_entry": USER_AGENT}) ``` **Important:** Use `user_agent_entry` (not `_user_agent_entry` which is deprecated). ## Connection URL Format ``` databricks://token:<access_token>@<server_hostname>?http_path=<path>&catalog=<catalog>&schema=<schema> ``` - `server_hostname`: Workspace host without `https://` (e.g., `myworkspace.cloud.databricks.com`) - `http_path`: SQL Warehouse HTTP path (e.g., `/sql/1.0/warehouses/abc123`) - `catalog` / `schema`: Optional default catalog and schema ## Environment Variables Reference **Common (all auth types):** ```bash DATABRICKS_HOST # Workspace URL (e.g., https://myworkspace.cloud.databricks.com) DATABRICKS_HTTP_PATH # SQL Warehouse HTTP path (e.g., /sql/1.0/warehouses/<id>) DATABRICKS_CATALOG # Optional: Default catalog (default: main) DATABRICKS_SCHEMA # Optional: Default schema (default: default) ``` **PAT Authentication:** ```bash DATABRICKS_TOKEN # Personal access token (starts with dapi...) ``` **OAuth M2M Authentication:** ```bash DATABRICKS_CLIENT_ID # Service Principal UUID DATABRICKS_CLIENT_SECRET # OAuth secret for the service principal ``` **OAuth U2M Custom OAuth App:** ```bash DATABRICKS_U2M_CLIENT_ID # Custom OAuth app client ID DATABRICKS_REDIRECT_URI # Optional: Redirect URI (default: http://localhost:8080/callback) DATABRICKS_U2M_CLIENT_SECRET # Optional: Required if OAuth app is confidential ``` **OAuth U2M Token-Env:** ```bash DATABRICKS_ACCESS_TOKEN # Pre-obtained OAuth access token ``` **Multi-Auth Selector:** ```bash APP_AUTH_TYPE # pat | oauth_m2m | oauth_u2m ``` **Note:** Use `APP_AUTH_TYPE` (not `DATABRICKS_AUTH_TYPE`) to avoid conflict with SDK's internal `auth_type` parameter. ## Host Normalization Helper SQLAlchemy connection URL requires bare hostname (no `https://`): ```python def normalize_host(host: str) -> str: """Normalize host to bare hostname for SQLAlchemy URL.""" return host.replace("https://", "").replace("http://", "").split("/")[0] # Usage server_hostname = normalize_host(os.environ.get("DATABRICKS_HOST", "")) url = f"databricks://token:{token}@{server_hostname}?http_path={http_path}" ``` ## Complete Examples ### Auth Type 1: PAT Authentication ```python import os from sqlalchemy import create_engine, text USER_AGENT = "YourCompany_YourProduct/1.0.0" def get_engine(): host = os.environ.get("DATABRICKS_HOST", "").strip() http_path = os.environ.get("DATABRICKS_HTTP_PATH", "").strip() token = os.environ.get("DATABRICKS_TOKEN", "").strip() if not host or not http_path or not token: raise ValueError("Set DATABRICKS_HOST, DATABRICKS_HTTP_PATH, and DATABRICKS_TOKEN") server_hostname = host.replace("https://", "").split("/")[0] catalog = os.environ.get("DATABRICKS_CATALOG", "main") schema = os.environ.get("DATABRICKS_SCHEMA", "default") url = f"databricks://token:{token}@{server_hostname}?http_path={http_path}&catalog={catalog}&schema={schema}" return create_engine(url, connect_args={"user_agent_entry": USER_AGENT}) with get_engine().connect() as conn: result = conn.execute(text("SELECT current_user()")) print(result.fetchall()) ``` ### Auth Type 2: OAuth M2M (Client Credentials) ```python import os from databricks.sdk.config import Config from sqlalchemy import create_engine, text USER_AGENT = "YourCompany_YourProduct/1.0.0" def get_access_token(): host = os.environ.get("DATABRICKS_HOST", "").strip() host_url = host if host.startswith("https://") else f"https://{host}" config = Config( host=host_url, client_id=os.environ.get("DATABRICKS_CLIENT_ID", ""), client_secret=os.environ.get("DATABRICKS_CLIENT_SECRET", ""), auth_type="oauth-m2m", # Required: prevents default credential resolution ) # authenticate() returns headers dict, NOT an object with .token headers = config.authenticate() return headers.get("Authorization", "").replace("Bearer ", "").strip() def get_engine(): host = os.environ.get("DATABRICKS_HOST", "").strip() http_path = os.environ.get("DATABRICKS_HTTP_PATH", "").strip() server_hostname = host.replace("https://", "").split("/")[0] access_token = get_access_token() url = f"databricks://token:{access_token}@{server_hostname}?http_path={http_path}&catalog=main&schema=default" return create_engine(url, connect_args={"user_agent_entry": USER_AGENT}) with get_engine().connect() as conn: result = conn.execute(text("SELECT current_user()")) print(result.fetchall()) ``` ### Auth Type 3: OAuth U2M Custom OAuth App (PKCE) ```python import os import base64 import hashlib import secrets import string import urllib.parse from http.server import HTTPServer, BaseHTTPRequestHandler from threading import Thread from urllib.parse import parse_qs, urlparse import requests import webbrowser from sqlalchemy import create_engine, text USER_AGENT = "YourCompany_YourProduct/1.0.0" DEFAULT_REDIRECT_URI = "http://localhost:8080/callback" def _pkce_verifier_and_challenge(): allowed = string.ascii_letters + string.digits + "-._~" code_verifier = "".join(secrets.choice(allowed) for _ in range(64)) digest = hashlib.sha256(code_verifier.encode()).digest() code_challenge = base64.urlsafe_b64encode(digest).decode().rstrip("=") return code_verifier, code_challenge def run_u2m_flow(host: str, client_id: str, redirect_uri: str = None, client_secret: str = None) -> dict: redirect_uri = redirect_uri or DEFAULT_REDIRECT_URI host = host.rstrip("/") if not host.startswith("https://"): host = "https://" + host code_verifier, code_challenge = _pkce_verifier_and_challenge() state = secrets.token_urlsafe(32) auth_url = f"{host}/oidc/v1/authorize?" + urllib.parse.urlencode({ "response_type": "code", "client_id": client_id, "redirect_uri": redirect_uri, "scope": "all-apis", "code_challenge": code_challenge, "code_challenge_method": "S256", "state": state, }) code_holder = [] parsed = urlparse(redirect_uri) port = parsed.port or 8080 class Handler(BaseHTTPRequestHandler): def do_GET(self): q = parse_qs(urlparse(self.path).query) code_holder.append(q.get("code", [None])[0]) self.send_response(200) self.end_headers() self.wfile.write(b"Authentication successful. Close this window.") def log_message(self, *args): pass server = HTTPServer(("localhost", port), Handler) thread = Thread(target=server.handle_request, daemon=True) thread.start() webbrowser.open(auth_url) thread.join(timeout=120) if not code_holder or not code_holder[0]: raise RuntimeError("No authorization code received") resp = requests.post( f"{host}/oidc/v1/token", data={ "grant_type": "authorization_code", "code": code_holder[0], "redirect_uri": redirect_uri, "client_id": client_id, "code_verifier": code_verifier, **({"client_secret": client_secret} if client_secret else {}), }, ) resp.raise_for_status() return resp.json() # Usage tokens = run_u2m_flow(
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub