uapi-sdk-python 0.1.1__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.
- uapi/__init__.py +2 -0
- uapi/client.py +2005 -0
- uapi/errors.py +153 -0
- uapi_sdk_python-0.1.1.dist-info/METADATA +82 -0
- uapi_sdk_python-0.1.1.dist-info/RECORD +7 -0
- uapi_sdk_python-0.1.1.dist-info/WHEEL +5 -0
- uapi_sdk_python-0.1.1.dist-info/top_level.txt +1 -0
uapi/errors.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any, Dict, Optional
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
class UapiError(Exception):
|
|
6
|
+
code: str
|
|
7
|
+
status: int
|
|
8
|
+
message: str
|
|
9
|
+
details: Optional[Dict[str, Any]]
|
|
10
|
+
|
|
11
|
+
def __init__(self, code: str, status: int, message: str, details: Optional[Dict[str, Any]] = None):
|
|
12
|
+
super().__init__(f"[{status}] {code}: {message}")
|
|
13
|
+
self.code = code
|
|
14
|
+
self.status = status
|
|
15
|
+
self.message = message
|
|
16
|
+
self.details = details
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ApiErrorError(UapiError):
|
|
20
|
+
"""上游/内部错误 (API_ERROR)"""
|
|
21
|
+
DEFAULT_STATUS = 502
|
|
22
|
+
|
|
23
|
+
class AvatarNotFoundError(UapiError):
|
|
24
|
+
"""头像未找到 (AVATAR_NOT_FOUND)"""
|
|
25
|
+
DEFAULT_STATUS = 404
|
|
26
|
+
|
|
27
|
+
class ConversionFailedError(UapiError):
|
|
28
|
+
"""转换失败 (CONVERSION_FAILED)"""
|
|
29
|
+
DEFAULT_STATUS = 400
|
|
30
|
+
|
|
31
|
+
class FileOpenErrorError(UapiError):
|
|
32
|
+
"""文件打开错误 (FILE_OPEN_ERROR)"""
|
|
33
|
+
DEFAULT_STATUS = 500
|
|
34
|
+
|
|
35
|
+
class FileRequiredError(UapiError):
|
|
36
|
+
"""文件必需 (FILE_REQUIRED)"""
|
|
37
|
+
DEFAULT_STATUS = 400
|
|
38
|
+
|
|
39
|
+
class InternalServerErrorError(UapiError):
|
|
40
|
+
"""服务器内部错误 (INTERNAL_SERVER_ERROR)"""
|
|
41
|
+
DEFAULT_STATUS = 500
|
|
42
|
+
|
|
43
|
+
class InvalidParameterError(UapiError):
|
|
44
|
+
"""请求参数错误 (INVALID_PARAMETER)"""
|
|
45
|
+
DEFAULT_STATUS = 400
|
|
46
|
+
|
|
47
|
+
class InvalidParamsError(UapiError):
|
|
48
|
+
"""无效参数 (INVALID_PARAMS)"""
|
|
49
|
+
DEFAULT_STATUS = 400
|
|
50
|
+
|
|
51
|
+
class NotFoundError(UapiError):
|
|
52
|
+
"""资源不存在 (NOT_FOUND)"""
|
|
53
|
+
DEFAULT_STATUS = 404
|
|
54
|
+
|
|
55
|
+
class NoMatchError(UapiError):
|
|
56
|
+
"""无匹配 (NO_MATCH)"""
|
|
57
|
+
DEFAULT_STATUS = 404
|
|
58
|
+
|
|
59
|
+
class NoTrackingDataError(UapiError):
|
|
60
|
+
"""无物流数据 (NO_TRACKING_DATA)"""
|
|
61
|
+
DEFAULT_STATUS = 404
|
|
62
|
+
|
|
63
|
+
class PhoneInfoFailedError(UapiError):
|
|
64
|
+
"""手机号信息查询失败 (PHONE_INFO_FAILED)"""
|
|
65
|
+
DEFAULT_STATUS = 500
|
|
66
|
+
|
|
67
|
+
class RecognitionFailedError(UapiError):
|
|
68
|
+
"""识别失败 (RECOGNITION_FAILED)"""
|
|
69
|
+
DEFAULT_STATUS = 404
|
|
70
|
+
|
|
71
|
+
class RequestEntityTooLargeError(UapiError):
|
|
72
|
+
"""错误 (REQUEST_ENTITY_TOO_LARGE)"""
|
|
73
|
+
DEFAULT_STATUS = 413
|
|
74
|
+
|
|
75
|
+
class ServiceBusyError(UapiError):
|
|
76
|
+
"""请求过于频繁 (SERVICE_BUSY)"""
|
|
77
|
+
DEFAULT_STATUS = 429
|
|
78
|
+
|
|
79
|
+
class TimezoneNotFoundError(UapiError):
|
|
80
|
+
"""时区未找到 (TIMEZONE_NOT_FOUND)"""
|
|
81
|
+
DEFAULT_STATUS = 404
|
|
82
|
+
|
|
83
|
+
class UnauthorizedError(UapiError):
|
|
84
|
+
"""请求未授权 (UNAUTHORIZED)"""
|
|
85
|
+
DEFAULT_STATUS = 401
|
|
86
|
+
|
|
87
|
+
class UnsupportedCarrierError(UapiError):
|
|
88
|
+
"""不支持的承运商 (UNSUPPORTED_CARRIER)"""
|
|
89
|
+
DEFAULT_STATUS = 404
|
|
90
|
+
|
|
91
|
+
class UnsupportedFormatError(UapiError):
|
|
92
|
+
"""格式不支持 (UNSUPPORTED_FORMAT)"""
|
|
93
|
+
DEFAULT_STATUS = 400
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def map_error(r: httpx.Response) -> UapiError:
|
|
97
|
+
code = None
|
|
98
|
+
msg = r.text
|
|
99
|
+
try:
|
|
100
|
+
data = r.json()
|
|
101
|
+
code = data.get("code") or data.get("error") or data.get("errCode") or "API_ERROR"
|
|
102
|
+
msg = data.get("message") or data.get("errMsg") or msg
|
|
103
|
+
details = data.get("details")
|
|
104
|
+
except Exception:
|
|
105
|
+
details = None
|
|
106
|
+
status = r.status_code
|
|
107
|
+
cls = _class_by_code(code, status)
|
|
108
|
+
return cls(code, status, msg, details)
|
|
109
|
+
|
|
110
|
+
def _class_by_code(code: str, status: int):
|
|
111
|
+
c = (code or "").upper()
|
|
112
|
+
mapping = {
|
|
113
|
+
|
|
114
|
+
"API_ERROR": ApiErrorError,
|
|
115
|
+
|
|
116
|
+
"AVATAR_NOT_FOUND": AvatarNotFoundError,
|
|
117
|
+
|
|
118
|
+
"CONVERSION_FAILED": ConversionFailedError,
|
|
119
|
+
|
|
120
|
+
"FILE_OPEN_ERROR": FileOpenErrorError,
|
|
121
|
+
|
|
122
|
+
"FILE_REQUIRED": FileRequiredError,
|
|
123
|
+
|
|
124
|
+
"INTERNAL_SERVER_ERROR": InternalServerErrorError,
|
|
125
|
+
|
|
126
|
+
"INVALID_PARAMETER": InvalidParameterError,
|
|
127
|
+
|
|
128
|
+
"INVALID_PARAMS": InvalidParamsError,
|
|
129
|
+
|
|
130
|
+
"NOT_FOUND": NotFoundError,
|
|
131
|
+
|
|
132
|
+
"NO_MATCH": NoMatchError,
|
|
133
|
+
|
|
134
|
+
"NO_TRACKING_DATA": NoTrackingDataError,
|
|
135
|
+
|
|
136
|
+
"PHONE_INFO_FAILED": PhoneInfoFailedError,
|
|
137
|
+
|
|
138
|
+
"RECOGNITION_FAILED": RecognitionFailedError,
|
|
139
|
+
|
|
140
|
+
"REQUEST_ENTITY_TOO_LARGE": RequestEntityTooLargeError,
|
|
141
|
+
|
|
142
|
+
"SERVICE_BUSY": ServiceBusyError,
|
|
143
|
+
|
|
144
|
+
"TIMEZONE_NOT_FOUND": TimezoneNotFoundError,
|
|
145
|
+
|
|
146
|
+
"UNAUTHORIZED": UnauthorizedError,
|
|
147
|
+
|
|
148
|
+
"UNSUPPORTED_CARRIER": UnsupportedCarrierError,
|
|
149
|
+
|
|
150
|
+
"UNSUPPORTED_FORMAT": UnsupportedFormatError,
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
return mapping.get(c) or ( {400: InvalidParameterError, 401: UnauthorizedError, 404: NotFoundError, 429: ServiceBusyError, 500: InternalServerError}.get(status) or UapiError )
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: uapi-sdk-python
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Idiomatic UAPI SDK for Python
|
|
5
|
+
Author-email: UAPI <dev@uapis.cn>
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: httpx>=0.24.1
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest; extra == "dev"
|
|
11
|
+
Requires-Dist: mypy; extra == "dev"
|
|
12
|
+
Requires-Dist: black; extra == "dev"
|
|
13
|
+
Requires-Dist: isort; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# uapi-sdk-python
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
[](https://www.python.org/)
|
|
20
|
+
[](https://uapis.cn/)
|
|
21
|
+
[](https://pypi.org/project/uapi-sdk-python/)
|
|
22
|
+
|
|
23
|
+
> [!NOTE]
|
|
24
|
+
> 所有接口的 Python 示例都可以在 [UApi](https://uapis.cn/docs/introduction) 的接口文档页面,向下滚动至 **快速启动** 区块后直接复制。
|
|
25
|
+
|
|
26
|
+
## 快速开始
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install uapi-sdk-python
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from uapi import UapiClient
|
|
34
|
+
|
|
35
|
+
client = UapiClient("https://uapis.cn/api/v1")
|
|
36
|
+
result = client.social.get_social_qq_userinfo(qq="10001")
|
|
37
|
+
print(result)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 特性
|
|
41
|
+
|
|
42
|
+
现在你不再需要反反复复的查阅文档了。
|
|
43
|
+
|
|
44
|
+
只需在 IDE 中键入 `client.`,所有核心模块——如 `social`、`game`、`image`——即刻同步展现。进一步输入即可直接定位到 `get_social_qq_userinfo` 这样的具体方法,其名称与文档的 `operationId` 严格保持一致,确保了开发过程的直观与高效。
|
|
45
|
+
|
|
46
|
+
所有方法签名只接受真实且必需的参数。当你在构建请求时,IDE 会即时提示 `qq`、`username` 等键名,这彻底杜绝了在 `dict`/关键字参数中因拼写错误而导致的运行时错误。
|
|
47
|
+
|
|
48
|
+
针对 401、404、429 等标准 HTTP 响应,SDK 已将其统一映射为具名的异常类型。这些异常均附带 `code`、`status`、`details` 等关键上下文信息,确保你在日志中能第一时间准确、快速地诊断问题。
|
|
49
|
+
|
|
50
|
+
`UapiClient(base_url, token, timeout)` 默认使用 `httpx` 并自动追加 `Authorization` 头;需要切换环境或调整超时时,只要改一次构造参数即可。
|
|
51
|
+
|
|
52
|
+
如果你需要查看字段细节或内部逻辑,仓库中的 `./internal` 目录同步保留了由 `openapi-generator` 生成的完整结构体,随时可供参考。
|
|
53
|
+
|
|
54
|
+
## 错误模型概览
|
|
55
|
+
|
|
56
|
+
| HTTP 状态码 | SDK 错误类型 | 附加信息 |
|
|
57
|
+
|-------------|----------------------------------------------|------------------------------------------------------------------------------------|
|
|
58
|
+
| 401/403 | `UnauthorizedError` | `code`、`status` |
|
|
59
|
+
| 404 | `NotFoundError` / `NoMatchError` | `code`、`status` |
|
|
60
|
+
| 400 | `InvalidParameterError` / `InvalidParamsError` | `code`、`status`、`details` |
|
|
61
|
+
| 429 | `ServiceBusyError` | `code`、`status`、`retry_after_seconds`(用于决定何时重试) |
|
|
62
|
+
| 5xx | `InternalServerErrorError` / `ApiErrorError` | `code`、`status`、`details` |
|
|
63
|
+
| 其他 4xx | `UapiError` | `code`、`status`、`details` |
|
|
64
|
+
|
|
65
|
+
## 其他 SDK
|
|
66
|
+
|
|
67
|
+
| 语言 | 仓库地址 |
|
|
68
|
+
|-------------|--------------------------------------------------------------|
|
|
69
|
+
| Go | https://github.com/AxT-Team/uapi-go-sdk |
|
|
70
|
+
| Python(当前) | https://github.com/AxT-Team/uapi-python-sdk |
|
|
71
|
+
| TypeScript| https://github.com/AxT-Team/uapi-typescript-sdk |
|
|
72
|
+
| Browser (TypeScript/JavaScript)| https://github.com/AxT-Team/uapi-browser-sdk |
|
|
73
|
+
| Java | https://github.com/AxT-Team/uapi-java-sdk |
|
|
74
|
+
| PHP | https://github.com/AxT-Team/uapi-php-sdk |
|
|
75
|
+
| C# | https://github.com/AxT-Team/uapi-csharp-sdk |
|
|
76
|
+
| C++ | https://github.com/AxT-Team/uapi-cpp-sdk |
|
|
77
|
+
| Rust | https://github.com/AxT-Team/uapi-rust-sdk |
|
|
78
|
+
|
|
79
|
+
## 文档
|
|
80
|
+
|
|
81
|
+
访问 [UApi文档首页](https://uapis.cn/docs/introduction) 并选择任意接口,向下滚动到 **快速启动** 区块即可看到最新的 Python 示例代码。
|
|
82
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
uapi/__init__.py,sha256=3dluUZfyWYYGTWzDBFip0d5YZej6waZiq2ayvJ0RI9o,86
|
|
2
|
+
uapi/client.py,sha256=yaOdgDNUvUnw3bXQPTJyO6paT3KnuPzkv-77Nk9eUPU,88187
|
|
3
|
+
uapi/errors.py,sha256=npeo8-u6-j0IZ4-H50rBuCWAB4kLG6pqpq0rlLX2ANw,4390
|
|
4
|
+
uapi_sdk_python-0.1.1.dist-info/METADATA,sha256=sjyeezSTjL8ybi4-S0605wpiGswlFynsaOthpHYanEY,4801
|
|
5
|
+
uapi_sdk_python-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
+
uapi_sdk_python-0.1.1.dist-info/top_level.txt,sha256=0TrPOLLMqin88fxqxR9T5piS4dSoyju9HFiPu1oPEUU,5
|
|
7
|
+
uapi_sdk_python-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
uapi
|