Source code for pybragerone.models.api.common
"""Common models shared across API modules."""
from __future__ import annotations
from typing import Any
from pydantic import BaseModel
[docs]
class ApiResponse[T](BaseModel):
"""Standard API response wrapper with status and data.
This wrapper provides a consistent interface for all API responses,
including HTTP status code, response data, and optional headers.
Examples:
Single object response:
>>> response: ApiResponse[User] = await client.get_user()
>>> if response.is_success:
... user = response.data
List response:
>>> response: ApiResponse[list[Module]] = await client.get_modules(obj_id)
>>> modules = response.data if response.is_success else []
Raw data response:
>>> response: ApiResponse[dict[str, Any]] = await client.get_parameters(...)
>>> params = response.data
Attributes:
status: HTTP status code (e.g., 200, 404, 500).
data: Response data of type T.
headers: Optional HTTP response headers.
"""
status: int
data: T
headers: dict[str, str] | None = None
@property
def is_success(self) -> bool:
"""Check if response was successful (2xx status).
Returns:
True if status is in range 200-299, False otherwise.
"""
return 200 <= self.status < 300
@property
def is_client_error(self) -> bool:
"""Check if response was client error (4xx status).
Returns:
True if status is in range 400-499, False otherwise.
"""
return 400 <= self.status < 500
@property
def is_server_error(self) -> bool:
"""Check if response was server error (5xx status).
Returns:
True if status is in range 500-599, False otherwise.
"""
return 500 <= self.status < 600
@property
def is_error(self) -> bool:
"""Check if response was any error (4xx or 5xx status).
Returns:
True if status is 400 or higher, False otherwise.
"""
return self.status >= 400
[docs]
class Permission(BaseModel):
"""Single permission string model for type safety.
Permissions in BragerOne API are uppercase strings with underscores,
such as 'DISPLAY_MENU_OBJECTS', 'SUBMISSION_CREATE', etc.
Automatically converts from string or dict format.
Examples:
From string:
>>> perm = Permission(name="DISPLAY_MENU_OBJECTS")
>>> perm = Permission.model_validate("DISPLAY_MENU_DHW")
From dict (API response):
>>> perm = Permission.model_validate({"name": "SUBMISSION_CREATE"})
As list (from API):
>>> perms = ["DISPLAY_MENU_CIRCUITS", "DISPLAY_PARAMETER_LEVEL_1"]
>>> permissions = [Permission.model_validate(p) for p in perms]
String representation:
>>> perm = Permission(name="DISPLAY_MENU_ALERTS")
>>> str(perm)
'DISPLAY_MENU_ALERTS'
"""
name: str
[docs]
@classmethod
def model_validate(cls, obj: Any, **kwargs: Any) -> Permission:
"""Validate and convert value to Permission.
Args:
obj: String, dict, or Permission instance.
**kwargs: Additional validation arguments.
Returns:
Permission instance.
Raises:
ValueError: If obj cannot be converted to Permission.
"""
if isinstance(obj, cls):
return obj
if isinstance(obj, str):
return cls(name=obj)
if isinstance(obj, dict):
return super().model_validate(obj, **kwargs)
raise ValueError(f"Cannot convert {type(obj)} to Permission")
def __str__(self) -> str:
"""Return the permission name when converted to string."""
return self.name
def __hash__(self) -> int:
"""Make Permission hashable for use in sets."""
return hash(self.name)
def __eq__(self, other: object) -> bool:
"""Compare permissions by name."""
if isinstance(other, Permission):
return self.name == other.name
if isinstance(other, str):
return self.name == other
return False