uapi-sdk-python 0.1.10__tar.gz → 0.1.13__tar.gz
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_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/PKG-INFO +1 -1
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/pyproject.toml +1 -1
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi/client.py +25 -86
- uapi_sdk_python-0.1.13/uapi/errors.py +335 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi_sdk_python.egg-info/PKG-INFO +1 -1
- uapi_sdk_python-0.1.10/uapi/errors.py +0 -153
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/README.md +0 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/setup.cfg +0 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/tests/test_client.py +0 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi/__init__.py +0 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi_sdk_python.egg-info/SOURCES.txt +0 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi_sdk_python.egg-info/dependency_links.txt +0 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi_sdk_python.egg-info/requires.txt +0 -0
- {uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi_sdk_python.egg-info/top_level.txt +0 -0
|
@@ -15,7 +15,8 @@ class _Config:
|
|
|
15
15
|
class _HTTP:
|
|
16
16
|
def __init__(self, cfg: _Config):
|
|
17
17
|
self._cfg = cfg
|
|
18
|
-
self._client = httpx.Client(timeout=cfg.timeout)
|
|
18
|
+
self._client = httpx.Client(timeout=cfg.timeout, trust_env=False)
|
|
19
|
+
self.last_response_meta: Optional[ResponseMeta] = None
|
|
19
20
|
|
|
20
21
|
def request(self, method: str, path: str, *, params: Dict[str, Any] | None = None, json: Any | None = None, headers: Dict[str, str] | None = None):
|
|
21
22
|
url = self._cfg.base_url.rstrip("/") + path
|
|
@@ -24,7 +25,10 @@ class _HTTP:
|
|
|
24
25
|
headers["Authorization"] = f"Bearer {self._cfg.token}"
|
|
25
26
|
r = self._client.request(method, url, params=params, json=json, headers=headers)
|
|
26
27
|
if r.status_code >= 400:
|
|
27
|
-
|
|
28
|
+
err = map_error(r)
|
|
29
|
+
self.last_response_meta = err.meta
|
|
30
|
+
raise err
|
|
31
|
+
self.last_response_meta = extract_meta(r.headers)
|
|
28
32
|
# try json else bytes
|
|
29
33
|
try:
|
|
30
34
|
return r.json()
|
|
@@ -90,6 +94,10 @@ class UapiClient:
|
|
|
90
94
|
self.zhi_neng_sou_suo = _zhi_neng_sou_suo
|
|
91
95
|
setattr(self, "智能搜索", _zhi_neng_sou_suo)
|
|
92
96
|
|
|
97
|
+
@property
|
|
98
|
+
def last_response_meta(self) -> Optional[ResponseMeta]:
|
|
99
|
+
return self._http.last_response_meta
|
|
100
|
+
|
|
93
101
|
|
|
94
102
|
class _ClipzyZaiXianJianTieBanApi:
|
|
95
103
|
def __init__(self, http: _HTTP):
|
|
@@ -428,12 +436,7 @@ class _ImageApi:
|
|
|
428
436
|
这个接口会获取 Bing 搜索引擎当天全球同步的每日壁纸,并直接以图片形式返回。你可以用它来做应用的启动页、网站背景,或者任何需要每日更新精美图片的地方。
|
|
429
437
|
|
|
430
438
|
## 使用须知
|
|
431
|
-
|
|
432
|
-
> [!NOTE]
|
|
433
|
-
> **响应格式是图片**
|
|
434
|
-
> 请注意,此接口成功时直接返回图片二进制数据(通常为 `image/jpeg`),而非 JSON 格式。请确保客户端能够正确处理。
|
|
435
|
-
|
|
436
|
-
我们内置了备用方案:如果从必应官方获取图片失败,系统会尝试返回一张预存的高质量风景图,以保证服务的稳定性。
|
|
439
|
+
此接口成功时直接返回图片二进制数据,通常是 `image/jpeg`,不是 JSON 格式。接入时请按图片响应来处理。
|
|
437
440
|
"""
|
|
438
441
|
params = {}
|
|
439
442
|
body = {}
|
|
@@ -472,21 +475,6 @@ class _ImageApi:
|
|
|
472
475
|
|
|
473
476
|
## 功能概述
|
|
474
477
|
你提供一段文本内容,我们为你生成对应的二维码图片。你可以自定义尺寸、前景色、背景色,还支持透明背景,并选择不同的返回格式以适应不同场景。
|
|
475
|
-
|
|
476
|
-
## 使用须知
|
|
477
|
-
|
|
478
|
-
> [!IMPORTANT]
|
|
479
|
-
> **关键参数 `format`**
|
|
480
|
-
> 此参数决定了成功响应的内容类型和结构,请务必根据你的需求选择并正确处理响应:
|
|
481
|
-
> - **`image`** (默认): 直接返回 `image/png` 格式的图片二进制数据,适合在 `<img>` 标签中直接使用。
|
|
482
|
-
> - **`json`**: 返回一个包含 Base64 Data URI 的 JSON 对象,适合需要在前端直接嵌入CSS或HTML的场景。
|
|
483
|
-
> - **`json_url`**: 返回一个包含图片临时URL的JSON对象,适合需要图片链接的场景。
|
|
484
|
-
|
|
485
|
-
> [!TIP]
|
|
486
|
-
> **颜色参数说明**
|
|
487
|
-
> - 颜色参数使用十六进制格式(如 `#FF0000`)
|
|
488
|
-
> - URL 中需要对 `#` 进行编码,即 `%23`(例如:`fgcolor=%23FF0000`)
|
|
489
|
-
> - 当 `transparent=true` 时,`bgcolor` 参数会被忽略
|
|
490
478
|
"""
|
|
491
479
|
params = {}
|
|
492
480
|
body = {}
|
|
@@ -638,9 +626,6 @@ class _ImageApi:
|
|
|
638
626
|
r"""图片敏感检测
|
|
639
627
|
这是一个图片内容审核接口,自动识别图片中的违规内容并返回处理建议。
|
|
640
628
|
|
|
641
|
-
> [!VIP]
|
|
642
|
-
> 此接口限时免费开放,无需企业认证即可使用。
|
|
643
|
-
|
|
644
629
|
## 功能概述
|
|
645
630
|
上传图片文件或提供图片URL,接口会自动分析图片内容,返回是否违规、风险等级和处理建议。适合对接到用户上传流程中,实现自动化内容审核。
|
|
646
631
|
|
|
@@ -872,19 +857,6 @@ class _MiscApi:
|
|
|
872
857
|
|
|
873
858
|
### 数据源列表
|
|
874
859
|
传 `sources=true`,返回所有支持历史数据的平台列表。
|
|
875
|
-
|
|
876
|
-
## 可选值
|
|
877
|
-
`type` 参数接受多种不同的值,每种值对应一个不同的热榜来源。以下是目前支持的所有值:
|
|
878
|
-
|
|
879
|
-
| 分类 | 支持的 type 值 |
|
|
880
|
-
|------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
881
|
-
| 视频/社区 | bilibili(哔哩哔哩弹幕网), acfun(A站弹幕视频网站), weibo(新浪微博热搜), zhihu(知乎热榜), zhihu-daily(知乎日报热榜), douyin(抖音热榜), kuaishou(快手热榜), douban-movie(豆瓣电影榜单), douban-group(豆瓣小组话题), tieba(百度贴吧热帖), hupu(虎扑热帖), ngabbs(NGA游戏论坛热帖), v2ex(V2EX技术社区热帖), 52pojie(吾爱破解热帖), hostloc(全球主机交流论坛), coolapk(酷安热榜) |
|
|
882
|
-
| 新闻/资讯 | baidu(百度热搜), thepaper(澎湃新闻热榜), toutiao(今日头条热榜), qq-news(腾讯新闻热榜), sina(新浪热搜), sina-news(新浪新闻热榜), netease-news(网易新闻热榜), huxiu(虎嗅网热榜), ifanr(爱范儿热榜) |
|
|
883
|
-
| 技术/IT | sspai(少数派热榜), ithome(IT之家热榜), ithome-xijiayi(IT之家·喜加一栏目), juejin(掘金社区热榜), jianshu(简书热榜), guokr(果壳热榜), 36kr(36氪热榜), 51cto(51CTO热榜), csdn(CSDN博客热榜), nodeseek(NodeSeek 技术社区), hellogithub(HelloGitHub 项目推荐) |
|
|
884
|
-
| 游戏 | lol(英雄联盟热帖), genshin(原神热榜), honkai(崩坏3热榜), starrail(星穹铁道热榜) |
|
|
885
|
-
| 音乐 | netease-music(网易云音乐热歌榜), qq-music(QQ音乐热歌榜) |
|
|
886
|
-
| 其他 | weread(微信读书热门书籍), weatheralarm(天气预警信息), earthquake(地震速报), history(历史上的今天) |
|
|
887
|
-
|
|
888
860
|
"""
|
|
889
861
|
params = {}
|
|
890
862
|
body = {}
|
|
@@ -1034,9 +1006,6 @@ graph TD
|
|
|
1034
1006
|
r"""获取支持的快递公司列表
|
|
1035
1007
|
不确定系统支持哪些快递公司?这个接口返回完整的支持列表。
|
|
1036
1008
|
|
|
1037
|
-
> [!VIP]
|
|
1038
|
-
> 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
|
|
1039
|
-
|
|
1040
1009
|
## 功能概述
|
|
1041
1010
|
获取系统当前支持的所有快递公司列表,包括每家公司的标准编码(code)和中文名称(name)。
|
|
1042
1011
|
|
|
@@ -1056,9 +1025,6 @@ graph TD
|
|
|
1056
1025
|
r"""识别快递公司
|
|
1057
1026
|
不确定手里的快递单号属于哪家快递公司?这个接口专门做识别,不查物流。
|
|
1058
1027
|
|
|
1059
|
-
> [!VIP]
|
|
1060
|
-
> 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
|
|
1061
|
-
|
|
1062
1028
|
## 功能概述
|
|
1063
1029
|
输入快递单号,系统会根据单号规则快速识别出最可能的快递公司。如果存在多个可能的匹配结果,还会在 `alternatives` 字段中返回备选项,供你参考选择。
|
|
1064
1030
|
|
|
@@ -1081,16 +1047,15 @@ graph TD
|
|
|
1081
1047
|
r"""查询快递物流信息
|
|
1082
1048
|
买了东西想知道快递到哪儿了?这个接口帮你实时追踪物流状态。
|
|
1083
1049
|
|
|
1084
|
-
> [!VIP]
|
|
1085
|
-
> 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
|
|
1086
|
-
|
|
1087
1050
|
## 功能概述
|
|
1088
|
-
|
|
1051
|
+
提供一个快递单号,系统会自动识别快递公司并返回完整的物流轨迹信息。这个接口目前可以查询中通、圆通、韵达、申通、极兔、京东、EMS、德邦等主流快递公司的物流信息。
|
|
1089
1052
|
|
|
1090
1053
|
## 使用须知
|
|
1054
|
+
目前暂不支持顺丰快递单号的物流查询。
|
|
1055
|
+
|
|
1091
1056
|
- **自动识别**:不知道是哪家快递?系统会根据单号规则自动识别快递公司(推荐使用)
|
|
1092
1057
|
- **手动指定**:如果已知快递公司,可以传递 `carrier_code` 参数,查询速度会更快
|
|
1093
|
-
-
|
|
1058
|
+
- **手机尾号验证**:部分快递公司需要验证收件人手机尾号才能查询详细物流,如果返回 `暂无物流信息`,建议尝试传入 `phone` 参数
|
|
1094
1059
|
- **查询时效**:物流信息实时查询,响应时间通常在1-2秒内
|
|
1095
1060
|
"""
|
|
1096
1061
|
params = {}
|
|
@@ -1123,9 +1088,9 @@ graph TD
|
|
|
1123
1088
|
|
|
1124
1089
|
## 可选功能模块
|
|
1125
1090
|
- `extended=true`:扩展气象字段(体感温度、能见度、气压、紫外线、空气质量及污染物分项数据)
|
|
1126
|
-
- `forecast=true`:多天预报(最多7
|
|
1091
|
+
- `forecast=true`:多天预报(最多7天,会额外返回每天的最高温度、最低温度,以及日出日落、风速等详细数据)
|
|
1127
1092
|
- `hourly=true`:逐小时预报(24小时)
|
|
1128
|
-
- `minutely=true
|
|
1093
|
+
- `minutely=true`:分钟级降水预报(仅国内城市,精确到2分钟)
|
|
1129
1094
|
- `indices=true`:18项生活指数(穿衣、紫外线、洗车、运动、花粉等)
|
|
1130
1095
|
|
|
1131
1096
|
## 天气字段说明
|
|
@@ -1133,7 +1098,7 @@ graph TD
|
|
|
1133
1098
|
|
|
1134
1099
|
常见值包括:晴、多云、阴、小雨、中雨、大雨、雷阵雨、小雪、中雪、大雪、雨夹雪、雾、霾、沙尘。
|
|
1135
1100
|
|
|
1136
|
-
|
|
1101
|
+
如果你的业务需要稳定的天气分类,建议使用 `weather_code` 进行映射。完整的天气图标代码请参考[天气图标代码表](#enum-list)。
|
|
1137
1102
|
"""
|
|
1138
1103
|
params = {}
|
|
1139
1104
|
body = {}
|
|
@@ -1770,10 +1735,7 @@ class _SocialApi:
|
|
|
1770
1735
|
|
|
1771
1736
|
def get_social_qq_groupinfo(self, **kwargs):
|
|
1772
1737
|
r"""查询 QQ 群信息
|
|
1773
|
-
想在你的应用里展示QQ
|
|
1774
|
-
|
|
1775
|
-
> [!VIP]
|
|
1776
|
-
> 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
|
|
1738
|
+
想在你的应用里展示QQ群信息?这个接口让你轻松获取群名称、群头像、群简介、成员数量等详细公开信息。
|
|
1777
1739
|
|
|
1778
1740
|
## 功能概述
|
|
1779
1741
|
你只需要提供一个QQ群号(5-12位纯数字),接口就会返回该群的完整公开信息。我们会先验证群号的有效性,确保返回的数据准确可靠。接口响应速度快,数据结构清晰,非常适合集成到各类应用场景中。
|
|
@@ -1813,9 +1775,6 @@ class _SocialApi:
|
|
|
1813
1775
|
r"""查询 QQ 信息
|
|
1814
1776
|
这是一个功能丰富的QQ用户信息查询接口,能够获取QQ用户的详细公开信息。
|
|
1815
1777
|
|
|
1816
|
-
> [!VIP]
|
|
1817
|
-
> 我们在近日优化了此接口,速度应该会更加快了。
|
|
1818
|
-
|
|
1819
1778
|
## 功能概述
|
|
1820
1779
|
通过QQ号查询用户的详细信息,包括基础资料、等级信息、VIP状态等。返回的信息丰富全面,适合用于用户画像分析、社交应用集成等场景。
|
|
1821
1780
|
|
|
@@ -2299,19 +2258,16 @@ class _TranslateApi:
|
|
|
2299
2258
|
r"""AI智能翻译
|
|
2300
2259
|
这是一个商业级的AI智能翻译服务,采用最新的神经网络翻译技术和大语言模型,提供远超传统机器翻译的质量。
|
|
2301
2260
|
|
|
2302
|
-
> [!VIP]
|
|
2303
|
-
> 本API目前处于**限时免费**阶段,我们鼓励开发者深度集成和测试。未来,它将转为付费API,为用户提供更稳定、更智能的翻译服务。
|
|
2304
|
-
|
|
2305
2261
|
## 功能概述
|
|
2306
2262
|
|
|
2307
|
-
-
|
|
2263
|
+
- **单文本翻译**: 专注处理单条文本翻译,适合需要高质量译文的业务场景。
|
|
2308
2264
|
- **多风格适配**: 提供随意口语化、专业商务、学术正式、文学艺术四种翻译风格,能够根据不同场景需求调整翻译的语言风格和表达方式。
|
|
2309
2265
|
- **上下文感知**: 支持通用、商务、技术、医疗、法律、市场营销、娱乐、教育、新闻等九种专业领域的上下文翻译,确保术语准确性和表达地道性。
|
|
2310
|
-
- **高质量保证**: 内置质量评估系统,对每次翻译结果进行流畅度、准确度、完整性评分,并提供置信度分数和替代翻译建议。
|
|
2311
|
-
- **智能解释**: 提供关键词组翻译注释、文化背景说明和语法结构分析,帮助用户理解翻译逻辑和文化差异。
|
|
2312
|
-
- **高效批量**: 批量翻译支持最多50条文本,总计10万字符,配备智能并发控制(1-10并发)和失败重试机制。
|
|
2313
|
-
- **快速模式**: 提供快速模式选项,在保证95%+准确率的前提下,响应时间缩短至800ms内,适合实时翻译和聊天应用。
|
|
2314
2266
|
- **格式保留**: 智能识别并保持原文的格式结构,包括换行、缩进、特殊符号等,确保翻译后的文本保持良好的可读性。
|
|
2267
|
+
|
|
2268
|
+
## 支持的语言
|
|
2269
|
+
|
|
2270
|
+
我们支持超过100种语言的互译,详见下方参数列表。
|
|
2315
2271
|
"""
|
|
2316
2272
|
params = {}
|
|
2317
2273
|
body = {}
|
|
@@ -2323,12 +2279,6 @@ class _TranslateApi:
|
|
|
2323
2279
|
if "context" in kwargs:
|
|
2324
2280
|
body["context"] = kwargs["context"]
|
|
2325
2281
|
|
|
2326
|
-
if "fast_mode" in kwargs:
|
|
2327
|
-
body["fast_mode"] = kwargs["fast_mode"]
|
|
2328
|
-
|
|
2329
|
-
if "max_concurrency" in kwargs:
|
|
2330
|
-
body["max_concurrency"] = kwargs["max_concurrency"]
|
|
2331
|
-
|
|
2332
2282
|
if "preserve_format" in kwargs:
|
|
2333
2283
|
body["preserve_format"] = kwargs["preserve_format"]
|
|
2334
2284
|
|
|
@@ -2341,9 +2291,6 @@ class _TranslateApi:
|
|
|
2341
2291
|
if "text" in kwargs:
|
|
2342
2292
|
body["text"] = kwargs["text"]
|
|
2343
2293
|
|
|
2344
|
-
if "texts" in kwargs:
|
|
2345
|
-
body["texts"] = kwargs["texts"]
|
|
2346
|
-
|
|
2347
2294
|
path = "/api/v1/ai/translate"
|
|
2348
2295
|
|
|
2349
2296
|
return self._http.request("POST", path, params=params, json=body if body else None)
|
|
@@ -2490,9 +2437,6 @@ class _WebparseApi:
|
|
|
2490
2437
|
|
|
2491
2438
|
## 功能概述
|
|
2492
2439
|
|
|
2493
|
-
> [!VIP]
|
|
2494
|
-
> 本 API 目前处于**限时免费**阶段,未来将转为付费服务。
|
|
2495
|
-
|
|
2496
2440
|
提交一个网页 URL,我们会自动抓取主体内容,剔除广告、导航栏等干扰元素,并转换为 Markdown 格式。同时会提取标题、作者、发布日期等元数据,生成 YAML Front Matter。
|
|
2497
2441
|
|
|
2498
2442
|
任务提交后会立即返回任务 ID,你可以用它来查询处理进度和结果。单个任务最长处理 60 秒,结果缓存 30 分钟。
|
|
@@ -2531,14 +2475,12 @@ class _MinGanCiShiBieApi:
|
|
|
2531
2475
|
r"""分析敏感词
|
|
2532
2476
|
分析单个或多个关键词的敏感程度,返回标准化风险标签与置信度结果。
|
|
2533
2477
|
|
|
2534
|
-
> [!VIP]
|
|
2535
|
-
> 本API基于先进的分析模型,提供三级缓存策略和并发处理能力。
|
|
2536
|
-
|
|
2537
2478
|
## 功能概述
|
|
2538
2479
|
|
|
2539
2480
|
- **模型驱动**: 使用先进的分析模型进行语义分析。
|
|
2540
2481
|
- **高性能**: 采用三级缓存策略(持久化存储 → 统一缓存 → 模型分析),确保高频请求的响应速度。
|
|
2541
2482
|
- **并发支持**: 支持批量并发处理,单次最多可分析100个关键词。
|
|
2483
|
+
- **输入限制**: 单条关键词最多 1,000 字符,总字符数最多 20,000。
|
|
2542
2484
|
- **标准标签**: 返回 `label` 字段,明确区分 `sensitive` 与 `normal`。
|
|
2543
2485
|
- **分类清晰**: 返回 `category` 字段,用于标识具体风险类别。
|
|
2544
2486
|
- **置信度输出**: 返回 `confidence` 字段,范围为0.0到1.0。
|
|
@@ -2635,9 +2577,6 @@ UAPI Pro Search 是一个智能搜索引擎,采用机器学习算法对搜索
|
|
|
2635
2577
|
- **时间范围过滤**: 支持按天/周/月/年过滤结果
|
|
2636
2578
|
- **站内搜索**: 支持 `site:` 操作符,在指定网站内搜索
|
|
2637
2579
|
- **文件类型过滤**: 支持 `filetype:` 操作符,快速找到 PDF、Word 等特定格式文件
|
|
2638
|
-
|
|
2639
|
-
> [!VIP]
|
|
2640
|
-
> 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
|
|
2641
2580
|
|
|
2642
2581
|
"""
|
|
2643
2582
|
params = {}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Any, Dict, Mapping, Optional
|
|
4
|
+
import httpx
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class RateLimitPolicyEntry:
|
|
8
|
+
name: str
|
|
9
|
+
quota: Optional[int] = None
|
|
10
|
+
unit: Optional[str] = None
|
|
11
|
+
window_seconds: Optional[int] = None
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class RateLimitStateEntry:
|
|
15
|
+
name: str
|
|
16
|
+
remaining: Optional[int] = None
|
|
17
|
+
unit: Optional[str] = None
|
|
18
|
+
reset_after_seconds: Optional[int] = None
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ResponseMeta:
|
|
22
|
+
request_id: Optional[str] = None
|
|
23
|
+
retry_after_seconds: Optional[int] = None
|
|
24
|
+
debit_status: Optional[str] = None
|
|
25
|
+
credits_requested: Optional[int] = None
|
|
26
|
+
credits_charged: Optional[int] = None
|
|
27
|
+
credits_pricing: Optional[str] = None
|
|
28
|
+
active_quota_buckets: Optional[int] = None
|
|
29
|
+
stop_on_empty: Optional[bool] = None
|
|
30
|
+
rate_limit_policy_raw: Optional[str] = None
|
|
31
|
+
rate_limit_raw: Optional[str] = None
|
|
32
|
+
rate_limit_policies: Dict[str, RateLimitPolicyEntry] = field(default_factory=dict)
|
|
33
|
+
rate_limits: Dict[str, RateLimitStateEntry] = field(default_factory=dict)
|
|
34
|
+
balance_limit_cents: Optional[int] = None
|
|
35
|
+
balance_remaining_cents: Optional[int] = None
|
|
36
|
+
quota_limit_credits: Optional[int] = None
|
|
37
|
+
quota_remaining_credits: Optional[int] = None
|
|
38
|
+
visitor_quota_limit_credits: Optional[int] = None
|
|
39
|
+
visitor_quota_remaining_credits: Optional[int] = None
|
|
40
|
+
raw_headers: Dict[str, str] = field(default_factory=dict)
|
|
41
|
+
|
|
42
|
+
class UapiError(Exception):
|
|
43
|
+
code: str
|
|
44
|
+
status: int
|
|
45
|
+
message: str
|
|
46
|
+
details: Any
|
|
47
|
+
payload: Any
|
|
48
|
+
meta: Optional[ResponseMeta]
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
code: str,
|
|
53
|
+
status: int,
|
|
54
|
+
message: str,
|
|
55
|
+
details: Any = None,
|
|
56
|
+
payload: Any = None,
|
|
57
|
+
meta: Optional[ResponseMeta] = None,
|
|
58
|
+
):
|
|
59
|
+
super().__init__(f"[{status}] {code}: {message}")
|
|
60
|
+
self.code = code
|
|
61
|
+
self.status = status
|
|
62
|
+
self.message = message
|
|
63
|
+
self.details = details
|
|
64
|
+
self.payload = payload
|
|
65
|
+
self.meta = meta
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ApiErrorError(UapiError):
|
|
69
|
+
"""上游/内部错误 (API_ERROR)"""
|
|
70
|
+
DEFAULT_STATUS = 502
|
|
71
|
+
|
|
72
|
+
class AvatarNotFoundError(UapiError):
|
|
73
|
+
"""头像未找到 (AVATAR_NOT_FOUND)"""
|
|
74
|
+
DEFAULT_STATUS = 404
|
|
75
|
+
|
|
76
|
+
class ConversionFailedError(UapiError):
|
|
77
|
+
"""转换失败 (CONVERSION_FAILED)"""
|
|
78
|
+
DEFAULT_STATUS = 400
|
|
79
|
+
|
|
80
|
+
class FileOpenErrorError(UapiError):
|
|
81
|
+
"""文件打开错误 (FILE_OPEN_ERROR)"""
|
|
82
|
+
DEFAULT_STATUS = 500
|
|
83
|
+
|
|
84
|
+
class FileRequiredError(UapiError):
|
|
85
|
+
"""文件必需 (FILE_REQUIRED)"""
|
|
86
|
+
DEFAULT_STATUS = 400
|
|
87
|
+
|
|
88
|
+
class InsufficientCreditsError(UapiError):
|
|
89
|
+
"""账户积分不足 (INSUFFICIENT_CREDITS)"""
|
|
90
|
+
DEFAULT_STATUS = 402
|
|
91
|
+
|
|
92
|
+
class InternalServerErrorError(UapiError):
|
|
93
|
+
"""服务器内部错误 (INTERNAL_SERVER_ERROR)"""
|
|
94
|
+
DEFAULT_STATUS = 500
|
|
95
|
+
|
|
96
|
+
class InvalidParameterError(UapiError):
|
|
97
|
+
"""请求参数错误 (INVALID_PARAMETER)"""
|
|
98
|
+
DEFAULT_STATUS = 400
|
|
99
|
+
|
|
100
|
+
class InvalidParamsError(UapiError):
|
|
101
|
+
"""无效参数 (INVALID_PARAMS)"""
|
|
102
|
+
DEFAULT_STATUS = 400
|
|
103
|
+
|
|
104
|
+
class NotFoundError(UapiError):
|
|
105
|
+
"""资源不存在 (NOT_FOUND)"""
|
|
106
|
+
DEFAULT_STATUS = 404
|
|
107
|
+
|
|
108
|
+
class NoMatchError(UapiError):
|
|
109
|
+
"""无匹配 (NO_MATCH)"""
|
|
110
|
+
DEFAULT_STATUS = 404
|
|
111
|
+
|
|
112
|
+
class NoTrackingDataError(UapiError):
|
|
113
|
+
"""无物流数据 (NO_TRACKING_DATA)"""
|
|
114
|
+
DEFAULT_STATUS = 404
|
|
115
|
+
|
|
116
|
+
class PhoneInfoFailedError(UapiError):
|
|
117
|
+
"""手机号信息查询失败 (PHONE_INFO_FAILED)"""
|
|
118
|
+
DEFAULT_STATUS = 500
|
|
119
|
+
|
|
120
|
+
class RecognitionFailedError(UapiError):
|
|
121
|
+
"""识别失败 (RECOGNITION_FAILED)"""
|
|
122
|
+
DEFAULT_STATUS = 404
|
|
123
|
+
|
|
124
|
+
class RequestEntityTooLargeError(UapiError):
|
|
125
|
+
"""错误 (REQUEST_ENTITY_TOO_LARGE)"""
|
|
126
|
+
DEFAULT_STATUS = 413
|
|
127
|
+
|
|
128
|
+
class ServiceBusyError(UapiError):
|
|
129
|
+
"""请求过于频繁 (SERVICE_BUSY)"""
|
|
130
|
+
DEFAULT_STATUS = 429
|
|
131
|
+
|
|
132
|
+
class TimezoneNotFoundError(UapiError):
|
|
133
|
+
"""时区未找到 (TIMEZONE_NOT_FOUND)"""
|
|
134
|
+
DEFAULT_STATUS = 404
|
|
135
|
+
|
|
136
|
+
class UnauthorizedError(UapiError):
|
|
137
|
+
"""请求未授权 (UNAUTHORIZED)"""
|
|
138
|
+
DEFAULT_STATUS = 401
|
|
139
|
+
|
|
140
|
+
class UnsupportedCarrierError(UapiError):
|
|
141
|
+
"""不支持的承运商 (UNSUPPORTED_CARRIER)"""
|
|
142
|
+
DEFAULT_STATUS = 404
|
|
143
|
+
|
|
144
|
+
class UnsupportedFormatError(UapiError):
|
|
145
|
+
"""格式不支持 (UNSUPPORTED_FORMAT)"""
|
|
146
|
+
DEFAULT_STATUS = 400
|
|
147
|
+
|
|
148
|
+
class VisitorMonthlyQuotaExhaustedError(UapiError):
|
|
149
|
+
"""访客月度免费额度已用尽 (VISITOR_MONTHLY_QUOTA_EXHAUSTED)"""
|
|
150
|
+
DEFAULT_STATUS = 429
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _default_code(status: int) -> str:
|
|
154
|
+
if status == 400:
|
|
155
|
+
return "INVALID_PARAMETER"
|
|
156
|
+
if status == 401:
|
|
157
|
+
return "UNAUTHORIZED"
|
|
158
|
+
if status == 402:
|
|
159
|
+
return "INSUFFICIENT_CREDITS"
|
|
160
|
+
if status == 404:
|
|
161
|
+
return "NOT_FOUND"
|
|
162
|
+
if status == 413:
|
|
163
|
+
return "REQUEST_ENTITY_TOO_LARGE"
|
|
164
|
+
if status == 429:
|
|
165
|
+
return "SERVICE_BUSY"
|
|
166
|
+
if status >= 500:
|
|
167
|
+
return "INTERNAL_SERVER_ERROR"
|
|
168
|
+
return "API_ERROR"
|
|
169
|
+
|
|
170
|
+
def _parse_int(value: Optional[str]) -> Optional[int]:
|
|
171
|
+
if value is None:
|
|
172
|
+
return None
|
|
173
|
+
try:
|
|
174
|
+
return int(value)
|
|
175
|
+
except (TypeError, ValueError):
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
def _parse_bool(value: Optional[str]) -> Optional[bool]:
|
|
179
|
+
if value is None:
|
|
180
|
+
return None
|
|
181
|
+
lowered = value.strip().lower()
|
|
182
|
+
if lowered == "true":
|
|
183
|
+
return True
|
|
184
|
+
if lowered == "false":
|
|
185
|
+
return False
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
def _unquote(value: str) -> str:
|
|
189
|
+
text = value.strip()
|
|
190
|
+
if len(text) >= 2 and text[0] == '"' and text[-1] == '"':
|
|
191
|
+
return text[1:-1]
|
|
192
|
+
return text
|
|
193
|
+
|
|
194
|
+
def _parse_structured_items(raw: Optional[str]) -> list[tuple[str, Dict[str, str]]]:
|
|
195
|
+
if not raw:
|
|
196
|
+
return []
|
|
197
|
+
items: list[tuple[str, Dict[str, str]]] = []
|
|
198
|
+
for chunk in [part.strip() for part in raw.split(",") if part.strip()]:
|
|
199
|
+
segments = [segment.strip() for segment in chunk.split(";") if segment.strip()]
|
|
200
|
+
if not segments:
|
|
201
|
+
continue
|
|
202
|
+
name = _unquote(segments[0])
|
|
203
|
+
params: Dict[str, str] = {}
|
|
204
|
+
for segment in segments[1:]:
|
|
205
|
+
if "=" not in segment:
|
|
206
|
+
continue
|
|
207
|
+
key, value = segment.split("=", 1)
|
|
208
|
+
params[key.strip()] = _unquote(value)
|
|
209
|
+
items.append((name, params))
|
|
210
|
+
return items
|
|
211
|
+
|
|
212
|
+
def extract_meta(headers: Mapping[str, str]) -> ResponseMeta:
|
|
213
|
+
raw_headers = {str(key).lower(): str(value) for key, value in headers.items()}
|
|
214
|
+
rate_limit_policies: Dict[str, RateLimitPolicyEntry] = {}
|
|
215
|
+
rate_limits: Dict[str, RateLimitStateEntry] = {}
|
|
216
|
+
|
|
217
|
+
for name, params in _parse_structured_items(raw_headers.get("ratelimit-policy")):
|
|
218
|
+
rate_limit_policies[name] = RateLimitPolicyEntry(
|
|
219
|
+
name=name,
|
|
220
|
+
quota=_parse_int(params.get("q")),
|
|
221
|
+
unit=params.get("uapi-unit"),
|
|
222
|
+
window_seconds=_parse_int(params.get("w")),
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
for name, params in _parse_structured_items(raw_headers.get("ratelimit")):
|
|
226
|
+
rate_limits[name] = RateLimitStateEntry(
|
|
227
|
+
name=name,
|
|
228
|
+
remaining=_parse_int(params.get("r")),
|
|
229
|
+
unit=params.get("uapi-unit"),
|
|
230
|
+
reset_after_seconds=_parse_int(params.get("t")),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return ResponseMeta(
|
|
234
|
+
request_id=raw_headers.get("x-request-id"),
|
|
235
|
+
retry_after_seconds=_parse_int(raw_headers.get("retry-after")),
|
|
236
|
+
debit_status=raw_headers.get("uapi-debit-status"),
|
|
237
|
+
credits_requested=_parse_int(raw_headers.get("uapi-credits-requested")),
|
|
238
|
+
credits_charged=_parse_int(raw_headers.get("uapi-credits-charged")),
|
|
239
|
+
credits_pricing=raw_headers.get("uapi-credits-pricing"),
|
|
240
|
+
active_quota_buckets=_parse_int(raw_headers.get("uapi-quota-active-buckets")),
|
|
241
|
+
stop_on_empty=_parse_bool(raw_headers.get("uapi-stop-on-empty")),
|
|
242
|
+
rate_limit_policy_raw=raw_headers.get("ratelimit-policy"),
|
|
243
|
+
rate_limit_raw=raw_headers.get("ratelimit"),
|
|
244
|
+
rate_limit_policies=rate_limit_policies,
|
|
245
|
+
rate_limits=rate_limits,
|
|
246
|
+
balance_limit_cents=rate_limit_policies.get("billing-balance").quota if "billing-balance" in rate_limit_policies else None,
|
|
247
|
+
balance_remaining_cents=rate_limits.get("billing-balance").remaining if "billing-balance" in rate_limits else None,
|
|
248
|
+
quota_limit_credits=rate_limit_policies.get("billing-quota").quota if "billing-quota" in rate_limit_policies else None,
|
|
249
|
+
quota_remaining_credits=rate_limits.get("billing-quota").remaining if "billing-quota" in rate_limits else None,
|
|
250
|
+
visitor_quota_limit_credits=rate_limit_policies.get("visitor-quota").quota if "visitor-quota" in rate_limit_policies else None,
|
|
251
|
+
visitor_quota_remaining_credits=rate_limits.get("visitor-quota").remaining if "visitor-quota" in rate_limits else None,
|
|
252
|
+
raw_headers=raw_headers,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
def _pick_details(data: Any) -> Any:
|
|
256
|
+
if not isinstance(data, dict):
|
|
257
|
+
return None
|
|
258
|
+
if "details" in data:
|
|
259
|
+
return data["details"]
|
|
260
|
+
if "quota" in data:
|
|
261
|
+
return data["quota"]
|
|
262
|
+
if "docs" in data:
|
|
263
|
+
return data["docs"]
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
def map_error(r: httpx.Response) -> UapiError:
|
|
267
|
+
code = None
|
|
268
|
+
msg = r.text
|
|
269
|
+
data: Any = None
|
|
270
|
+
try:
|
|
271
|
+
data = r.json()
|
|
272
|
+
code = data.get("code") or data.get("error") or data.get("errCode") or _default_code(r.status_code)
|
|
273
|
+
msg = data.get("message") or data.get("errMsg") or msg
|
|
274
|
+
except Exception:
|
|
275
|
+
code = _default_code(r.status_code)
|
|
276
|
+
status = r.status_code
|
|
277
|
+
meta = extract_meta(r.headers)
|
|
278
|
+
cls = _class_by_code(code, status)
|
|
279
|
+
return cls(code, status, msg, _pick_details(data), data, meta)
|
|
280
|
+
|
|
281
|
+
def _class_by_code(code: str, status: int):
|
|
282
|
+
c = (code or "").upper()
|
|
283
|
+
mapping = {
|
|
284
|
+
|
|
285
|
+
"API_ERROR": ApiErrorError,
|
|
286
|
+
|
|
287
|
+
"AVATAR_NOT_FOUND": AvatarNotFoundError,
|
|
288
|
+
|
|
289
|
+
"CONVERSION_FAILED": ConversionFailedError,
|
|
290
|
+
|
|
291
|
+
"FILE_OPEN_ERROR": FileOpenErrorError,
|
|
292
|
+
|
|
293
|
+
"FILE_REQUIRED": FileRequiredError,
|
|
294
|
+
|
|
295
|
+
"INSUFFICIENT_CREDITS": InsufficientCreditsError,
|
|
296
|
+
|
|
297
|
+
"INTERNAL_SERVER_ERROR": InternalServerErrorError,
|
|
298
|
+
|
|
299
|
+
"INVALID_PARAMETER": InvalidParameterError,
|
|
300
|
+
|
|
301
|
+
"INVALID_PARAMS": InvalidParamsError,
|
|
302
|
+
|
|
303
|
+
"NOT_FOUND": NotFoundError,
|
|
304
|
+
|
|
305
|
+
"NO_MATCH": NoMatchError,
|
|
306
|
+
|
|
307
|
+
"NO_TRACKING_DATA": NoTrackingDataError,
|
|
308
|
+
|
|
309
|
+
"PHONE_INFO_FAILED": PhoneInfoFailedError,
|
|
310
|
+
|
|
311
|
+
"RECOGNITION_FAILED": RecognitionFailedError,
|
|
312
|
+
|
|
313
|
+
"REQUEST_ENTITY_TOO_LARGE": RequestEntityTooLargeError,
|
|
314
|
+
|
|
315
|
+
"SERVICE_BUSY": ServiceBusyError,
|
|
316
|
+
|
|
317
|
+
"TIMEZONE_NOT_FOUND": TimezoneNotFoundError,
|
|
318
|
+
|
|
319
|
+
"UNAUTHORIZED": UnauthorizedError,
|
|
320
|
+
|
|
321
|
+
"UNSUPPORTED_CARRIER": UnsupportedCarrierError,
|
|
322
|
+
|
|
323
|
+
"UNSUPPORTED_FORMAT": UnsupportedFormatError,
|
|
324
|
+
|
|
325
|
+
"VISITOR_MONTHLY_QUOTA_EXHAUSTED": VisitorMonthlyQuotaExhaustedError,
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
return mapping.get(c) or ({
|
|
329
|
+
400: InvalidParameterError,
|
|
330
|
+
401: UnauthorizedError,
|
|
331
|
+
402: InsufficientCreditsError,
|
|
332
|
+
404: NotFoundError,
|
|
333
|
+
429: ServiceBusyError,
|
|
334
|
+
500: InternalServerErrorError,
|
|
335
|
+
}.get(status) or UapiError)
|
|
@@ -1,153 +0,0 @@
|
|
|
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: InternalServerErrorError}.get(status) or UapiError )
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{uapi_sdk_python-0.1.10 → uapi_sdk_python-0.1.13}/uapi_sdk_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|