matrx-api 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
matrx_api/errors.py ADDED
@@ -0,0 +1,88 @@
1
+ """The one error model. Mirrors MatrxApiError / OrganizationContextError of @ai-matrx/api."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ def _non_blank(value: Any) -> str | None:
9
+ return value if isinstance(value, str) and value.strip() else None
10
+
11
+
12
+ def extract_error_message(detail: Any) -> str | None:
13
+ """Richest human-readable message from a Matrx/FastAPI error body (same order as the TS client)."""
14
+ if not isinstance(detail, dict):
15
+ return None
16
+ candidates: list[str] = []
17
+
18
+ def push(v: str | None) -> None:
19
+ if v:
20
+ candidates.append(v)
21
+
22
+ push(_non_blank(detail.get("user_message")))
23
+ push(_non_blank(detail.get("message")))
24
+ details = detail.get("details")
25
+ if isinstance(details, list):
26
+ msgs = []
27
+ for entry in details:
28
+ if not isinstance(entry, dict):
29
+ continue
30
+ m = _non_blank(entry.get("message"))
31
+ if not m:
32
+ continue
33
+ f = _non_blank(entry.get("field"))
34
+ msgs.append(f"{f}: {m}" if f else m)
35
+ if msgs:
36
+ push("; ".join(msgs))
37
+ inner = detail.get("detail")
38
+ if isinstance(inner, dict):
39
+ push(_non_blank(inner.get("message")) or _non_blank(inner.get("user_message")))
40
+ if isinstance(inner, str) and inner.strip():
41
+ push(inner)
42
+ if isinstance(inner, list):
43
+ msgs = [m for e in inner if isinstance(e, dict) and (m := _non_blank(e.get("msg")))]
44
+ if msgs:
45
+ push("; ".join(msgs))
46
+ return candidates[0] if candidates else None
47
+
48
+
49
+ def extract_error_code(detail: Any) -> str | None:
50
+ """Machine code: top-level ``code``, else ``detail.code``."""
51
+ if not isinstance(detail, dict):
52
+ return None
53
+ top = _non_blank(detail.get("code"))
54
+ if top:
55
+ return top
56
+ inner = detail.get("detail")
57
+ if isinstance(inner, dict):
58
+ return _non_blank(inner.get("code"))
59
+ return None
60
+
61
+
62
+ class MatrxApiError(Exception):
63
+ """Every failed call: HTTP status, server code and message. ``status`` is 0 for a transport failure."""
64
+
65
+ def __init__(
66
+ self,
67
+ *,
68
+ status: int,
69
+ path: str,
70
+ server_detail: Any = None,
71
+ message: str | None = None,
72
+ code: str | None = None,
73
+ ) -> None:
74
+ self.status = status
75
+ self.path = path
76
+ self.server_detail = server_detail
77
+ self.code = code or extract_error_code(server_detail)
78
+ self.message = message or extract_error_message(server_detail) or f"HTTP {status}"
79
+ super().__init__(f"{self.message} [{status}{' ' + self.code if self.code else ''}] {path}")
80
+
81
+
82
+ class OrganizationContextError(Exception):
83
+ """Raised BEFORE the wire when an org-required operation has no (valid) organization."""
84
+
85
+ def __init__(self, code: str, message: str) -> None:
86
+ self.code = code
87
+ self.message = message
88
+ super().__init__(f"{message} [{code}]")
@@ -0,0 +1 @@
1
+ """One module per x-matrx-domain: ``from matrx_api.generated import files``. Generated - do not edit."""