2
0
Files
gitcaddy-server/sdk/python/gitea/exceptions.py
logikonline ad82306b52 feat(sdk): add CLI tool and SDK libraries for developer tooling (Phase 4)
Add comprehensive developer tooling for Gitea integration:

CLI Tool (cmd/gitea-cli/):
- gitea-cli auth login/logout/status - Authentication management
- gitea-cli upload release-asset - Chunked upload with progress
- gitea-cli upload resume - Resume interrupted uploads
- gitea-cli upload list - List pending upload sessions
- Parallel chunk uploads with configurable workers
- SHA256 checksum verification
- Progress bar with speed and ETA display

Go SDK (sdk/go/):
- GiteaClient with token authentication
- User, Repository, Release, Attachment types
- ChunkedUpload with parallel workers
- Progress callbacks for upload tracking
- Functional options pattern (WithChunkSize, WithParallel, etc.)

Python SDK (sdk/python/):
- GiteaClient with requests-based HTTP
- Full type hints and dataclasses
- ThreadPoolExecutor for parallel uploads
- Resume capability for interrupted uploads
- Exception hierarchy (APIError, UploadError, etc.)

TypeScript SDK (sdk/typescript/):
- Full TypeScript types and interfaces
- Async/await API design
- Browser and Node.js compatible
- Web Crypto API for checksums
- ESM and CJS build outputs

All SDKs support:
- Chunked uploads for large files
- Parallel upload workers
- Progress tracking with callbacks
- Checksum verification
- Resume interrupted uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 12:07:07 -05:00

91 lines
2.6 KiB
Python

# Copyright 2026 The Gitea Authors. All rights reserved.
# SPDX-License-Identifier: MIT
"""Exception classes for the Gitea SDK."""
from typing import Optional, Dict, Any
class GiteaError(Exception):
"""Base exception for all Gitea SDK errors."""
def __init__(self, message: str):
self.message = message
super().__init__(message)
class APIError(GiteaError):
"""Raised when the API returns an error response."""
def __init__(
self,
message: str,
code: Optional[str] = None,
status: int = 0,
details: Optional[Dict[str, Any]] = None,
):
super().__init__(message)
self.code = code
self.status = status
self.details = details or {}
def __str__(self) -> str:
if self.code:
return f"[{self.code}] {self.message}"
return self.message
class AuthenticationError(APIError):
"""Raised when authentication fails."""
def __init__(self, message: str = "Authentication failed", code: str = "AUTH_FAILED"):
super().__init__(message, code=code, status=401)
class NotFoundError(APIError):
"""Raised when a resource is not found."""
def __init__(self, resource: str, identifier: str = ""):
message = f"{resource} not found"
if identifier:
message = f"{resource} '{identifier}' not found"
super().__init__(message, code="NOT_FOUND", status=404)
self.resource = resource
self.identifier = identifier
class ValidationError(APIError):
"""Raised when request validation fails."""
def __init__(self, message: str, field: Optional[str] = None):
super().__init__(message, code="VALIDATION_FAILED", status=400)
self.field = field
class UploadError(GiteaError):
"""Raised when an upload fails."""
def __init__(self, message: str, session_id: Optional[str] = None, chunk: Optional[int] = None):
super().__init__(message)
self.session_id = session_id
self.chunk = chunk
def __str__(self) -> str:
parts = [self.message]
if self.session_id:
parts.append(f"session={self.session_id}")
if self.chunk is not None:
parts.append(f"chunk={self.chunk}")
return " ".join(parts)
class RateLimitError(APIError):
"""Raised when rate limit is exceeded."""
def __init__(self, retry_after: Optional[int] = None):
message = "Rate limit exceeded"
if retry_after:
message += f". Retry after {retry_after} seconds"
super().__init__(message, code="RATE_LIMIT_EXCEEDED", status=429)
self.retry_after = retry_after