refactor: rename project from Freepik to Magnific
Rename all identifiers, strings, file names, env vars, CLI entry point, ASCII banner, and API endpoint to reflect the company rebrand. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"""Magnific HTTP client with authentication, error handling, and download support."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
import httpx
|
||||
|
||||
from magnific_cli import __version__
|
||||
|
||||
BASE_URL = "https://api.magnific.ai"
|
||||
DEFAULT_TIMEOUT = 60.0
|
||||
|
||||
|
||||
class MagnificAPIError(Exception):
|
||||
"""Raised when the Magnific API returns an error response."""
|
||||
|
||||
def __init__(self, message: str, status_code: Optional[int] = None, raw: Optional[dict] = None):
|
||||
super().__init__(message)
|
||||
self.status_code = status_code
|
||||
self.raw = raw or {}
|
||||
|
||||
@classmethod
|
||||
def from_response(cls, response: httpx.Response) -> "MagnificAPIError":
|
||||
try:
|
||||
body = response.json()
|
||||
except Exception:
|
||||
body = {}
|
||||
|
||||
message = (
|
||||
body.get("message")
|
||||
or body.get("error", {}).get("message")
|
||||
or body.get("errors", [{}])[0].get("message")
|
||||
or f"HTTP {response.status_code}"
|
||||
)
|
||||
|
||||
# Append individual field validation errors when present
|
||||
invalid = body.get("invalid_params", [])
|
||||
if invalid:
|
||||
details = "\n".join(
|
||||
f" • {p.get('field', '?')}: {p.get('reason', '')}" for p in invalid
|
||||
)
|
||||
message = f"{message}\n\n{details}"
|
||||
|
||||
hints = {
|
||||
401: "Check your API key — set MAGNIFIC_API_KEY or use --api-key.",
|
||||
403: "Your plan may not support this feature. Check your Magnific subscription.",
|
||||
429: "Rate limit exceeded. Please wait before retrying.",
|
||||
}
|
||||
hint = hints.get(response.status_code)
|
||||
if hint:
|
||||
message = f"{message}\n\nHint: {hint}"
|
||||
|
||||
return cls(message, status_code=response.status_code, raw=body)
|
||||
|
||||
|
||||
class MagnificClient:
|
||||
"""Thin synchronous HTTP wrapper around the Magnific API."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api_key: str,
|
||||
base_url: str = BASE_URL,
|
||||
timeout: float = DEFAULT_TIMEOUT,
|
||||
) -> None:
|
||||
self._client = httpx.Client(
|
||||
base_url=base_url,
|
||||
headers={
|
||||
"x-magnific-api-key": api_key,
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
"User-Agent": f"magnific-cli/{__version__}",
|
||||
},
|
||||
timeout=httpx.Timeout(timeout),
|
||||
)
|
||||
|
||||
def post(self, path: str, json: dict[str, Any]) -> dict[str, Any]:
|
||||
try:
|
||||
response = self._client.post(path, json=json)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPStatusError as exc:
|
||||
raise MagnificAPIError.from_response(exc.response) from exc
|
||||
except httpx.RequestError as exc:
|
||||
raise MagnificAPIError(f"Network error: {exc}") from exc
|
||||
|
||||
def post_multipart(self, path: str, data: dict[str, Any], files: dict[str, Any]) -> dict[str, Any]:
|
||||
"""POST with multipart/form-data (for file uploads)."""
|
||||
headers = {k: v for k, v in self._client.headers.items() if k.lower() != "content-type"}
|
||||
try:
|
||||
response = self._client.post(path, data=data, files=files, headers=headers)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPStatusError as exc:
|
||||
raise MagnificAPIError.from_response(exc.response) from exc
|
||||
except httpx.RequestError as exc:
|
||||
raise MagnificAPIError(f"Network error: {exc}") from exc
|
||||
|
||||
def get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
try:
|
||||
response = self._client.get(path, params=params)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPStatusError as exc:
|
||||
raise MagnificAPIError.from_response(exc.response) from exc
|
||||
except httpx.RequestError as exc:
|
||||
raise MagnificAPIError(f"Network error: {exc}") from exc
|
||||
|
||||
def __enter__(self) -> "MagnificClient":
|
||||
return self
|
||||
|
||||
def __exit__(self, *args: Any) -> None:
|
||||
self._client.close()
|
||||
|
||||
def close(self) -> None:
|
||||
self._client.close()
|
||||
Reference in New Issue
Block a user