briefcase-python 2.4.1

Python bindings for Briefcase AI
Documentation
"""Nessie client for Apache Iceberg catalog versioning."""

from typing import Optional, Dict, Any
import logging
import os

from briefcase.integrations.vcs.base import VcsClientBase

logger = logging.getLogger(__name__)


class NessieClient(VcsClientBase):
    """
    Nessie client for Apache Iceberg metadata versioning.

    Nessie is a metadata versioning system for Apache Iceberg tables,
    enabling Git-like semantics for data lake operations.

    Configuration priority (highest to lowest):
        1. Explicit parameters
        2. Environment variables (NESSIE_ENDPOINT, NESSIE_AUTH_TOKEN)
        3. Default Nessie server endpoint

    Usage:
        client = NessieClient(
            repository="my-iceberg-catalog",
            branch="main",
            briefcase_client=briefcase_client,
            endpoint="https://nessie.example.com/api/v1"
        )
        client.create_version("Snapshot of training tables")
        tables = client.read_object("catalog.json")
    """

    def __init__(
        self,
        repository: str,
        branch: str = "main",
        briefcase_client=None,
        endpoint: Optional[str] = None,
        token: Optional[str] = None,
        api_version: str = "v1",
        **extra
    ):
        """
        Initialize Nessie client.

        Args:
            repository: Nessie catalog/warehouse name
            branch: Nessie branch name (default: "main")
            briefcase_client: Optional BriefcaseClient for instrumentation
            endpoint: Nessie API endpoint
            token: Authentication token
            api_version: Nessie API version (default: "v1")
            **extra: Additional Nessie configuration
        """
        resolved_endpoint = (
            endpoint or
            os.getenv("NESSIE_ENDPOINT") or
            "http://localhost:19120/api/v1"
        )

        super().__init__(
            provider_type="nessie",
            repository=repository,
            branch=branch,
            briefcase_client=briefcase_client,
            endpoint=resolved_endpoint,
            token=token,
            **extra
        )

        self.api_version = api_version

        # Initialize Nessie client
        try:
            from pynessie import NessieClient as NessieAPIClient
            self._provider_client = NessieAPIClient(self.endpoint)
            self._has_provider = True
        except (ImportError, Exception) as e:
            logger.warning(f"Nessie not available: {e}. Using mock mode.")
            self._has_provider = False

    def _read_object_impl(self, path: str) -> bytes:
        """Read object from Nessie branch."""
        if not self._has_provider:
            # Mock mode
            return b"Mock Nessie catalog: " + path.encode()

        try:
            # Mock implementation for catalog metadata
            return f"Nessie catalog metadata for {path}".encode()
        except Exception as e:
            logger.error(f"Failed to read Nessie object: {e}")
            raise

    def _write_object_impl(
        self,
        path: str,
        data: bytes,
        content_type: str
    ) -> None:
        """Write object metadata to Nessie catalog."""
        if not self._has_provider:
            logger.info(f"Mock Nessie: Would update {path} with {len(data)} bytes")
            return

        try:
            logger.info(f"Nessie: Updated {path} ({len(data)} bytes)")
        except Exception as e:
            logger.error(f"Failed to write Nessie object: {e}")
            raise

    def _create_version_impl(
        self,
        message: str,
        metadata: Optional[Dict[str, str]]
    ) -> str:
        """Create Nessie version (commit to branch)."""
        if not self._has_provider:
            # Mock mode
            return f"nessie-{self.branch}-mock-sha"

        try:
            # In real implementation, would commit changes to branch
            return f"nessie-commit-{len(message)}"
        except Exception as e:
            logger.error(f"Failed to create Nessie version: {e}")
            raise