py-wecom-toolkit 3.0.2__tar.gz → 3.0.3__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.
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/PKG-INFO +11 -11
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/README.md +10 -10
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/async_basic.py +6 -6
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/async_file.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/async_text.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/basic.py +6 -6
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/file.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/image.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/markdown.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/markdown_v2.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/news.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/template_card.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/text.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/voice.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/pyproject.toml +1 -1
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/__init__.py +14 -14
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/__init__.py +2 -2
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/client.py +19 -19
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/exceptions.py +6 -6
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/media.py +6 -6
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/message.py +3 -3
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/models.py +6 -6
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/token.py +10 -10
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/webhook/__init__.py +11 -11
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/webhook/client.py +54 -54
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/webhook/exceptions.py +8 -8
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/webhook/models.py +2 -2
- py_wecom_toolkit-3.0.2/EXAMPLES.md +0 -41
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/.gitignore +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/LICENSE +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/server/.env.example +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/server/basic_async.py +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/server/basic_sync.py +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/server/config.py +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/server/send_message.py +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/server/upload_file.py +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/.env.example +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/config.py +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/examples/webhook/test_image.png +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/server/cache.py +0 -0
- {py_wecom_toolkit-3.0.2 → py_wecom_toolkit-3.0.3}/src/py_wecom_toolkit/webhook/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: py-wecom-toolkit
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.3
|
|
4
4
|
Summary: 企业微信 Python 扩展包 - 支持 Webhook 与 Server 端 API
|
|
5
5
|
Project-URL: Homepage, https://gitee.com/guolei19850528/py_wecom_toolkit
|
|
6
6
|
Project-URL: Documentation, https://gitee.com/guolei19850528/py_wecom_toolkit#readme
|
|
@@ -72,7 +72,7 @@ py-wecom-toolkit/
|
|
|
72
72
|
│ ├── __init__.py # 包入口,导出所有公共类
|
|
73
73
|
│ ├── webhook/ # Webhook 消息发送模块(原“群机器人”)
|
|
74
74
|
│ │ ├── __init__.py
|
|
75
|
-
│ │ ├── client.py #
|
|
75
|
+
│ │ ├── client.py # WeComWebhookClient / AsyncWeComWebhookClient
|
|
76
76
|
│ │ ├── exceptions.py # Webhook 异常定义
|
|
77
77
|
│ │ ├── models.py # pydantic v2 消息模型(8种消息类型)
|
|
78
78
|
│ │ └── types.py # 类型别名
|
|
@@ -152,7 +152,7 @@ pip install py-wecom-toolkit[dev]
|
|
|
152
152
|
- 支持全部 8 种 Webhook 消息类型: text, markdown, markdown_v2, image, news, file, voice, template_card
|
|
153
153
|
- 基于 pydantic v2 的消息模型验证
|
|
154
154
|
- 基于 httpx 的异步 HTTP 客户端
|
|
155
|
-
- 同步与异步客户端双模式支持 (`
|
|
155
|
+
- 同步与异步客户端双模式支持 (`WeComWebhookClient` / `AsyncWeComWebhookClient`)
|
|
156
156
|
- 消息发送支持 @ 成员列表合并与去重
|
|
157
157
|
- 文件上传接口 (base64 编码 + md5 校验)
|
|
158
158
|
|
|
@@ -171,10 +171,10 @@ pip install py-wecom-toolkit[dev]
|
|
|
171
171
|
|
|
172
172
|
```python
|
|
173
173
|
import asyncio
|
|
174
|
-
from py_wecom_toolkit import
|
|
174
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
175
175
|
|
|
176
176
|
async def main():
|
|
177
|
-
client =
|
|
177
|
+
client = WeComWebhookClient(key="你的webhook_key")
|
|
178
178
|
|
|
179
179
|
# 发送文本消息
|
|
180
180
|
await client.send_text("Hello, World!")
|
|
@@ -214,10 +214,10 @@ asyncio.run(main())
|
|
|
214
214
|
### Webhook 消息发送 (同步)
|
|
215
215
|
|
|
216
216
|
```python
|
|
217
|
-
from py_wecom_toolkit import
|
|
217
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
218
218
|
|
|
219
219
|
# 创建同步客户端,支持上下文管理器自动管理连接池
|
|
220
|
-
with
|
|
220
|
+
with WeComWebhookClient(key="你的webhook_key") as client:
|
|
221
221
|
|
|
222
222
|
# 发送文本消息
|
|
223
223
|
resp = client.send_text("Hello, World!")
|
|
@@ -337,15 +337,15 @@ asyncio.run(main())
|
|
|
337
337
|
|
|
338
338
|
```python
|
|
339
339
|
import httpx
|
|
340
|
-
from py_wecom_toolkit import
|
|
340
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
341
341
|
|
|
342
342
|
# 使用自定义 httpx 客户端
|
|
343
343
|
async with httpx.AsyncClient(timeout=30.0) as http_client:
|
|
344
|
-
client =
|
|
344
|
+
client = WeComWebhookClient(key="xxx", client=http_client)
|
|
345
345
|
await client.send_text("使用自定义客户端")
|
|
346
346
|
|
|
347
347
|
# 使用上下文管理器
|
|
348
|
-
async with
|
|
348
|
+
async with WeComWebhookClient(key="xxx") as client:
|
|
349
349
|
await client.send_text("自动管理连接池")
|
|
350
350
|
|
|
351
351
|
# 使用 diskcache 缓存 access_token
|
|
@@ -369,7 +369,7 @@ client = WeComServerClient(
|
|
|
369
369
|
|
|
370
370
|
## API 参考
|
|
371
371
|
|
|
372
|
-
###
|
|
372
|
+
### WeComWebhookClient / AsyncWeComWebhookClient
|
|
373
373
|
|
|
374
374
|
| 方法 | 说明 |
|
|
375
375
|
|------|------|
|
|
@@ -20,7 +20,7 @@ py-wecom-toolkit/
|
|
|
20
20
|
│ ├── __init__.py # 包入口,导出所有公共类
|
|
21
21
|
│ ├── webhook/ # Webhook 消息发送模块(原“群机器人”)
|
|
22
22
|
│ │ ├── __init__.py
|
|
23
|
-
│ │ ├── client.py #
|
|
23
|
+
│ │ ├── client.py # WeComWebhookClient / AsyncWeComWebhookClient
|
|
24
24
|
│ │ ├── exceptions.py # Webhook 异常定义
|
|
25
25
|
│ │ ├── models.py # pydantic v2 消息模型(8种消息类型)
|
|
26
26
|
│ │ └── types.py # 类型别名
|
|
@@ -100,7 +100,7 @@ pip install py-wecom-toolkit[dev]
|
|
|
100
100
|
- 支持全部 8 种 Webhook 消息类型: text, markdown, markdown_v2, image, news, file, voice, template_card
|
|
101
101
|
- 基于 pydantic v2 的消息模型验证
|
|
102
102
|
- 基于 httpx 的异步 HTTP 客户端
|
|
103
|
-
- 同步与异步客户端双模式支持 (`
|
|
103
|
+
- 同步与异步客户端双模式支持 (`WeComWebhookClient` / `AsyncWeComWebhookClient`)
|
|
104
104
|
- 消息发送支持 @ 成员列表合并与去重
|
|
105
105
|
- 文件上传接口 (base64 编码 + md5 校验)
|
|
106
106
|
|
|
@@ -119,10 +119,10 @@ pip install py-wecom-toolkit[dev]
|
|
|
119
119
|
|
|
120
120
|
```python
|
|
121
121
|
import asyncio
|
|
122
|
-
from py_wecom_toolkit import
|
|
122
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
123
123
|
|
|
124
124
|
async def main():
|
|
125
|
-
client =
|
|
125
|
+
client = WeComWebhookClient(key="你的webhook_key")
|
|
126
126
|
|
|
127
127
|
# 发送文本消息
|
|
128
128
|
await client.send_text("Hello, World!")
|
|
@@ -162,10 +162,10 @@ asyncio.run(main())
|
|
|
162
162
|
### Webhook 消息发送 (同步)
|
|
163
163
|
|
|
164
164
|
```python
|
|
165
|
-
from py_wecom_toolkit import
|
|
165
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
166
166
|
|
|
167
167
|
# 创建同步客户端,支持上下文管理器自动管理连接池
|
|
168
|
-
with
|
|
168
|
+
with WeComWebhookClient(key="你的webhook_key") as client:
|
|
169
169
|
|
|
170
170
|
# 发送文本消息
|
|
171
171
|
resp = client.send_text("Hello, World!")
|
|
@@ -285,15 +285,15 @@ asyncio.run(main())
|
|
|
285
285
|
|
|
286
286
|
```python
|
|
287
287
|
import httpx
|
|
288
|
-
from py_wecom_toolkit import
|
|
288
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
289
289
|
|
|
290
290
|
# 使用自定义 httpx 客户端
|
|
291
291
|
async with httpx.AsyncClient(timeout=30.0) as http_client:
|
|
292
|
-
client =
|
|
292
|
+
client = WeComWebhookClient(key="xxx", client=http_client)
|
|
293
293
|
await client.send_text("使用自定义客户端")
|
|
294
294
|
|
|
295
295
|
# 使用上下文管理器
|
|
296
|
-
async with
|
|
296
|
+
async with WeComWebhookClient(key="xxx") as client:
|
|
297
297
|
await client.send_text("自动管理连接池")
|
|
298
298
|
|
|
299
299
|
# 使用 diskcache 缓存 access_token
|
|
@@ -317,7 +317,7 @@ client = WeComServerClient(
|
|
|
317
317
|
|
|
318
318
|
## API 参考
|
|
319
319
|
|
|
320
|
-
###
|
|
320
|
+
### WeComWebhookClient / AsyncWeComWebhookClient
|
|
321
321
|
|
|
322
322
|
| 方法 | 说明 |
|
|
323
323
|
|------|------|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: UTF-8 -*-
|
|
3
|
-
"""异步基础方法演示 - 展示
|
|
3
|
+
"""异步基础方法演示 - 展示 AsyncWeComWebhookClient 的基本用法."""
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import asyncio
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import AsyncWeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -24,13 +24,13 @@ async def main() -> None:
|
|
|
24
24
|
|
|
25
25
|
# 方式一: 异步上下文管理器 (推荐)
|
|
26
26
|
print("=== 方式一: 异步上下文管理器 ===")
|
|
27
|
-
async with
|
|
27
|
+
async with AsyncWeComWebhookClient(key=key) as client:
|
|
28
28
|
response = await client.send_text(_wrap(f"[异步基础测试] 上下文管理器 - {current_time}", current_time))
|
|
29
29
|
print(f"结果: errcode={response.errcode}, errmsg={response.errmsg}")
|
|
30
30
|
|
|
31
31
|
# 方式二: 手动管理连接
|
|
32
32
|
print("\n=== 方式二: 手动管理连接 ===")
|
|
33
|
-
client =
|
|
33
|
+
client = AsyncWeComWebhookClient(key=key)
|
|
34
34
|
try:
|
|
35
35
|
response = await client.send_text(_wrap(f"[异步基础测试] 手动连接 - {current_time}", current_time))
|
|
36
36
|
print(f"结果: errcode={response.errcode}, errmsg={response.errmsg}")
|
|
@@ -39,7 +39,7 @@ async def main() -> None:
|
|
|
39
39
|
|
|
40
40
|
# 方式三: 自定义配置
|
|
41
41
|
print("\n=== 方式三: 自定义配置 ===")
|
|
42
|
-
client =
|
|
42
|
+
client = AsyncWeComWebhookClient(
|
|
43
43
|
key=key,
|
|
44
44
|
timeout=30.0, # 自定义超时
|
|
45
45
|
mentioned_list=["@all"], # 默认 @所有人
|
|
@@ -52,7 +52,7 @@ async def main() -> None:
|
|
|
52
52
|
|
|
53
53
|
# 方式四: 使用原始 dict 发送
|
|
54
54
|
print("\n=== 方式四: 原始 dict 发送 ===")
|
|
55
|
-
async with
|
|
55
|
+
async with AsyncWeComWebhookClient(key=key) as client:
|
|
56
56
|
response = await client.send({
|
|
57
57
|
"msgtype": "text",
|
|
58
58
|
"text": {"content": _wrap(f"[异步基础测试] 原始dict - {current_time}", current_time)},
|
|
@@ -8,7 +8,7 @@ import asyncio
|
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
|
-
from py_wecom_toolkit import
|
|
11
|
+
from py_wecom_toolkit import AsyncWeComWebhookClient
|
|
12
12
|
|
|
13
13
|
from config import get_webhook_key
|
|
14
14
|
|
|
@@ -18,7 +18,7 @@ async def main() -> None:
|
|
|
18
18
|
key = get_webhook_key()
|
|
19
19
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
20
20
|
|
|
21
|
-
async with
|
|
21
|
+
async with AsyncWeComWebhookClient(key=key) as client:
|
|
22
22
|
# 创建测试文件
|
|
23
23
|
test_file = Path(__file__).parent / "async_test_upload.txt"
|
|
24
24
|
test_file.write_text(f"这是异步测试文件\n创建时间: {current_time}")
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import asyncio
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import AsyncWeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ async def main() -> None:
|
|
|
22
22
|
key = get_webhook_key()
|
|
23
23
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
24
24
|
|
|
25
|
-
async with
|
|
25
|
+
async with AsyncWeComWebhookClient(key=key) as client:
|
|
26
26
|
# 1. 纯文本消息
|
|
27
27
|
print("1. 发送纯文本消息")
|
|
28
28
|
resp = await client.send_text(_wrap(f"[异步文本测试] 纯文本消息 - {current_time}", current_time))
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: UTF-8 -*-
|
|
3
|
-
"""基础方法演示 - 展示
|
|
3
|
+
"""基础方法演示 - 展示 WeComWebhookClient 的基本用法."""
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import asyncio
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -24,13 +24,13 @@ async def main() -> None:
|
|
|
24
24
|
|
|
25
25
|
# 方式一: 上下文管理器 (推荐)
|
|
26
26
|
print("=== 方式一: 上下文管理器 ===")
|
|
27
|
-
async with
|
|
27
|
+
async with WeComWebhookClient(key=key) as client:
|
|
28
28
|
response = await client.send_text(_wrap(f"[基础测试] 上下文管理器 - {current_time}", current_time))
|
|
29
29
|
print(f"结果: errcode={response.errcode}, errmsg={response.errmsg}")
|
|
30
30
|
|
|
31
31
|
# 方式二: 手动管理连接
|
|
32
32
|
print("\n=== 方式二: 手动管理连接 ===")
|
|
33
|
-
client =
|
|
33
|
+
client = WeComWebhookClient(key=key)
|
|
34
34
|
try:
|
|
35
35
|
response = await client.send_text(_wrap(f"[基础测试] 手动连接 - {current_time}", current_time))
|
|
36
36
|
print(f"结果: errcode={response.errcode}, errmsg={response.errmsg}")
|
|
@@ -39,7 +39,7 @@ async def main() -> None:
|
|
|
39
39
|
|
|
40
40
|
# 方式三: 自定义配置
|
|
41
41
|
print("\n=== 方式三: 自定义配置 ===")
|
|
42
|
-
client =
|
|
42
|
+
client = WeComWebhookClient(
|
|
43
43
|
key=key,
|
|
44
44
|
timeout=30.0, # 自定义超时
|
|
45
45
|
mentioned_list=["@all"], # 默认 @所有人
|
|
@@ -52,7 +52,7 @@ async def main() -> None:
|
|
|
52
52
|
|
|
53
53
|
# 方式四: 使用原始 dict 发送
|
|
54
54
|
print("\n=== 方式四: 原始 dict 发送 ===")
|
|
55
|
-
async with
|
|
55
|
+
async with WeComWebhookClient(key=key) as client:
|
|
56
56
|
response = await client.send({
|
|
57
57
|
"msgtype": "text",
|
|
58
58
|
"text": {"content": _wrap(f"[基础测试] 原始dict - {current_time}", current_time)},
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ def main() -> None:
|
|
|
22
22
|
key = get_webhook_key()
|
|
23
23
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
24
24
|
|
|
25
|
-
with
|
|
25
|
+
with WeComWebhookClient(key=key) as client:
|
|
26
26
|
# 创建测试文件
|
|
27
27
|
test_file = Path(__file__).parent / "test_upload.txt"
|
|
28
28
|
test_file.write_text(f"这是一个测试文件\n创建时间: {current_time}")
|
|
@@ -8,7 +8,7 @@ import base64
|
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
|
-
from py_wecom_toolkit import
|
|
11
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
12
12
|
|
|
13
13
|
from config import get_webhook_key
|
|
14
14
|
|
|
@@ -23,7 +23,7 @@ def main() -> None:
|
|
|
23
23
|
key = get_webhook_key()
|
|
24
24
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
25
25
|
|
|
26
|
-
with
|
|
26
|
+
with WeComWebhookClient(key=key) as client:
|
|
27
27
|
# 1. 从文件发送图片
|
|
28
28
|
print("1. 发送本地图片文件")
|
|
29
29
|
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import asyncio
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ async def main() -> None:
|
|
|
22
22
|
key = get_webhook_key()
|
|
23
23
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
24
24
|
|
|
25
|
-
async with
|
|
25
|
+
async with WeComWebhookClient(key=key) as client:
|
|
26
26
|
# 1. 标题
|
|
27
27
|
print("1. 发送标题")
|
|
28
28
|
resp = await client.send_markdown(_wrap(
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import asyncio
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ async def main() -> None:
|
|
|
22
22
|
key = get_webhook_key()
|
|
23
23
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
24
24
|
|
|
25
|
-
async with
|
|
25
|
+
async with WeComWebhookClient(key=key) as client:
|
|
26
26
|
# 1. 标题
|
|
27
27
|
print("1. 发送标题")
|
|
28
28
|
resp = await client.send_markdown_v2(_wrap(
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import time
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -24,7 +24,7 @@ def main() -> None:
|
|
|
24
24
|
key = get_webhook_key()
|
|
25
25
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
26
26
|
|
|
27
|
-
with
|
|
27
|
+
with WeComWebhookClient(key=key) as client:
|
|
28
28
|
# 1. 单条图文
|
|
29
29
|
print("1. 发送单条图文")
|
|
30
30
|
resp = client.send_news([
|
|
@@ -6,7 +6,7 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
|
|
9
|
-
from py_wecom_toolkit import
|
|
9
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
10
10
|
|
|
11
11
|
from config import get_webhook_key
|
|
12
12
|
|
|
@@ -21,7 +21,7 @@ def main() -> None:
|
|
|
21
21
|
key = get_webhook_key()
|
|
22
22
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
23
23
|
|
|
24
|
-
with
|
|
24
|
+
with WeComWebhookClient(key=key) as client:
|
|
25
25
|
# 1. 文本通知卡片
|
|
26
26
|
print("1. 发送文本通知卡片")
|
|
27
27
|
text_notice_card = {
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import asyncio
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ async def main() -> None:
|
|
|
22
22
|
key = get_webhook_key()
|
|
23
23
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
24
24
|
|
|
25
|
-
async with
|
|
25
|
+
async with WeComWebhookClient(key=key) as client:
|
|
26
26
|
# 1. 纯文本消息
|
|
27
27
|
print("1. 发送纯文本消息")
|
|
28
28
|
resp = await client.send_text(_wrap(f"[文本消息] 这是一条纯文本消息 - {current_time}", current_time))
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
|
-
from py_wecom_toolkit import
|
|
10
|
+
from py_wecom_toolkit import WeComWebhookClient
|
|
11
11
|
|
|
12
12
|
from config import get_webhook_key
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ def main() -> None:
|
|
|
22
22
|
key = get_webhook_key()
|
|
23
23
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
24
24
|
|
|
25
|
-
with
|
|
25
|
+
with WeComWebhookClient(key=key) as client:
|
|
26
26
|
# 注意: 语音文件需要是 AMR 格式, 不超过 2MB, 时长不超过 60s
|
|
27
27
|
# 这里使用示例路径, 请替换为实际的 AMR 文件
|
|
28
28
|
voice_file = Path(__file__).parent / "test_voice.amr"
|
|
@@ -11,12 +11,12 @@ from .server.models import (
|
|
|
11
11
|
MediaUploadResponse,
|
|
12
12
|
MessageSendRequest,
|
|
13
13
|
MessageSendResponse,
|
|
14
|
-
|
|
14
|
+
WeComServerResponse,
|
|
15
15
|
)
|
|
16
16
|
from .server.token import AccessTokenManager
|
|
17
|
-
from .webhook.client import
|
|
17
|
+
from .webhook.client import AsyncWeComWebhookClient, WeComWebhookClient
|
|
18
18
|
from .webhook.models import (
|
|
19
|
-
|
|
19
|
+
WeComWebhookResponse,
|
|
20
20
|
UploadResponse,
|
|
21
21
|
MessageType,
|
|
22
22
|
TextMessage,
|
|
@@ -29,17 +29,17 @@ from .webhook.models import (
|
|
|
29
29
|
TemplateCardMessage,
|
|
30
30
|
)
|
|
31
31
|
from .webhook.exceptions import (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
WeComWebhookError,
|
|
33
|
+
WeComWebhookAPIError,
|
|
34
|
+
WeComWebhookRateLimitError,
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
-
__version__ = "3.0.
|
|
37
|
+
__version__ = "3.0.3"
|
|
38
38
|
|
|
39
39
|
__all__ = [
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
40
|
+
"WeComWebhookClient",
|
|
41
|
+
"AsyncWeComWebhookClient",
|
|
42
|
+
"WeComWebhookResponse",
|
|
43
43
|
"UploadResponse",
|
|
44
44
|
"MessageType",
|
|
45
45
|
"TextMessage",
|
|
@@ -50,15 +50,15 @@ __all__ = [
|
|
|
50
50
|
"FileMessage",
|
|
51
51
|
"VoiceMessage",
|
|
52
52
|
"TemplateCardMessage",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
53
|
+
"WeComWebhookError",
|
|
54
|
+
"WeComWebhookAPIError",
|
|
55
|
+
"WeComWebhookRateLimitError",
|
|
56
56
|
"WeComServerClient",
|
|
57
57
|
"AsyncWeComServerClient",
|
|
58
58
|
"MessageSendMixin",
|
|
59
59
|
"MediaMixin",
|
|
60
60
|
"AccessTokenManager",
|
|
61
|
-
"
|
|
61
|
+
"WeComServerResponse",
|
|
62
62
|
"AccessTokenResponse",
|
|
63
63
|
"IPListResponse",
|
|
64
64
|
"MediaUploadResponse",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
from .client import AsyncWeComServerClient, WeComServerClient
|
|
10
10
|
from .token import AccessTokenManager
|
|
11
11
|
from .models import (
|
|
12
|
-
|
|
12
|
+
WeComServerResponse,
|
|
13
13
|
AccessTokenResponse,
|
|
14
14
|
IPListResponse,
|
|
15
15
|
MediaUploadResponse,
|
|
@@ -24,7 +24,7 @@ __all__ = [
|
|
|
24
24
|
"AccessTokenManager",
|
|
25
25
|
"MessageSendMixin",
|
|
26
26
|
"MediaMixin",
|
|
27
|
-
"
|
|
27
|
+
"WeComServerResponse",
|
|
28
28
|
"AccessTokenResponse",
|
|
29
29
|
"IPListResponse",
|
|
30
30
|
"MediaUploadResponse",
|
|
@@ -18,8 +18,8 @@ from typing import Any
|
|
|
18
18
|
import httpx
|
|
19
19
|
|
|
20
20
|
from .cache import MemoryCache, TokenCache
|
|
21
|
-
from .exceptions import
|
|
22
|
-
from .models import IPListResponse,
|
|
21
|
+
from .exceptions import WeComServerAPIError, WeComServerConfigError, WeComServerNetworkError
|
|
22
|
+
from .models import IPListResponse, WeComServerResponse
|
|
23
23
|
from .message import MessageSendMixin
|
|
24
24
|
from .media import MediaMixin
|
|
25
25
|
from .token import AccessTokenManager
|
|
@@ -44,9 +44,9 @@ class _BaseServerClient(MessageSendMixin, MediaMixin):
|
|
|
44
44
|
base_url: str = BASE_URL,
|
|
45
45
|
) -> None:
|
|
46
46
|
if not corpid:
|
|
47
|
-
raise
|
|
47
|
+
raise WeComServerConfigError("corpid 不能为空")
|
|
48
48
|
if not corpsecret and not access_token:
|
|
49
|
-
raise
|
|
49
|
+
raise WeComServerConfigError("corpsecret 和 access_token 至少需提供一个")
|
|
50
50
|
self._corpid = corpid
|
|
51
51
|
self._corpsecret = corpsecret
|
|
52
52
|
self._timeout = timeout
|
|
@@ -86,11 +86,11 @@ class _BaseServerClient(MessageSendMixin, MediaMixin):
|
|
|
86
86
|
return await self._token_manager.async_get_token()
|
|
87
87
|
|
|
88
88
|
def _check_response(
|
|
89
|
-
self, data: dict[str, Any], model: type[
|
|
90
|
-
) ->
|
|
89
|
+
self, data: dict[str, Any], model: type[WeComServerResponse]
|
|
90
|
+
) -> WeComServerResponse:
|
|
91
91
|
resp = model(**data)
|
|
92
92
|
if not resp.ok:
|
|
93
|
-
raise
|
|
93
|
+
raise WeComServerAPIError(resp.errcode, resp.errmsg)
|
|
94
94
|
return resp
|
|
95
95
|
|
|
96
96
|
# ------------------------------------------------------------------
|
|
@@ -241,7 +241,7 @@ class WeComServerClient(_BaseServerClient):
|
|
|
241
241
|
response = self._client.get(url, params=params)
|
|
242
242
|
response.raise_for_status()
|
|
243
243
|
except httpx.HTTPError as exc:
|
|
244
|
-
raise
|
|
244
|
+
raise WeComServerNetworkError(f"GET 请求失败: {exc}", exc) from exc
|
|
245
245
|
return response.json()
|
|
246
246
|
|
|
247
247
|
def _get_bytes(self, url: str, params: dict[str, Any]) -> bytes:
|
|
@@ -249,7 +249,7 @@ class WeComServerClient(_BaseServerClient):
|
|
|
249
249
|
response = self._client.get(url, params=params)
|
|
250
250
|
response.raise_for_status()
|
|
251
251
|
except httpx.HTTPError as exc:
|
|
252
|
-
raise
|
|
252
|
+
raise WeComServerNetworkError(f"GET 下载失败: {exc}", exc) from exc
|
|
253
253
|
return response.content
|
|
254
254
|
|
|
255
255
|
def _post_json(
|
|
@@ -259,7 +259,7 @@ class WeComServerClient(_BaseServerClient):
|
|
|
259
259
|
response = self._client.post(url, params=params, json=json)
|
|
260
260
|
response.raise_for_status()
|
|
261
261
|
except httpx.HTTPError as exc:
|
|
262
|
-
raise
|
|
262
|
+
raise WeComServerNetworkError(f"POST 请求失败: {exc}", exc) from exc
|
|
263
263
|
return response.json()
|
|
264
264
|
|
|
265
265
|
def _post_files(
|
|
@@ -269,7 +269,7 @@ class WeComServerClient(_BaseServerClient):
|
|
|
269
269
|
response = self._client.post(url, params=params, files=files)
|
|
270
270
|
response.raise_for_status()
|
|
271
271
|
except httpx.HTTPError as exc:
|
|
272
|
-
raise
|
|
272
|
+
raise WeComServerNetworkError(f"文件上传失败: {exc}", exc) from exc
|
|
273
273
|
return response.json()
|
|
274
274
|
|
|
275
275
|
|
|
@@ -325,27 +325,27 @@ class AsyncWeComServerClient(_BaseServerClient):
|
|
|
325
325
|
await self._client.aclose()
|
|
326
326
|
|
|
327
327
|
def _get(self, url: str, params: dict[str, Any]) -> dict[str, Any]:
|
|
328
|
-
raise
|
|
328
|
+
raise WeComServerConfigError("异步客户端请使用 async_get")
|
|
329
329
|
|
|
330
330
|
def _get_bytes(self, url: str, params: dict[str, Any]) -> bytes:
|
|
331
|
-
raise
|
|
331
|
+
raise WeComServerConfigError("异步客户端请使用 async_get_bytes")
|
|
332
332
|
|
|
333
333
|
def _post_json(
|
|
334
334
|
self, url: str, params: dict[str, Any], json: dict[str, Any]
|
|
335
335
|
) -> dict[str, Any]:
|
|
336
|
-
raise
|
|
336
|
+
raise WeComServerConfigError("异步客户端请使用 async_post_json")
|
|
337
337
|
|
|
338
338
|
def _post_files(
|
|
339
339
|
self, url: str, params: dict[str, Any], files: dict[str, Any]
|
|
340
340
|
) -> dict[str, Any]:
|
|
341
|
-
raise
|
|
341
|
+
raise WeComServerConfigError("异步客户端请使用 async_post_files")
|
|
342
342
|
|
|
343
343
|
async def async_get(self, url: str, params: dict[str, Any]) -> dict[str, Any]:
|
|
344
344
|
try:
|
|
345
345
|
response = await self._client.get(url, params=params)
|
|
346
346
|
response.raise_for_status()
|
|
347
347
|
except httpx.HTTPError as exc:
|
|
348
|
-
raise
|
|
348
|
+
raise WeComServerNetworkError(f"GET 请求失败: {exc}", exc) from exc
|
|
349
349
|
return response.json()
|
|
350
350
|
|
|
351
351
|
async def async_get_bytes(self, url: str, params: dict[str, Any]) -> bytes:
|
|
@@ -353,7 +353,7 @@ class AsyncWeComServerClient(_BaseServerClient):
|
|
|
353
353
|
response = await self._client.get(url, params=params)
|
|
354
354
|
response.raise_for_status()
|
|
355
355
|
except httpx.HTTPError as exc:
|
|
356
|
-
raise
|
|
356
|
+
raise WeComServerNetworkError(f"GET 下载失败: {exc}", exc) from exc
|
|
357
357
|
return response.content
|
|
358
358
|
|
|
359
359
|
async def async_post_json(
|
|
@@ -363,7 +363,7 @@ class AsyncWeComServerClient(_BaseServerClient):
|
|
|
363
363
|
response = await self._client.post(url, params=params, json=json)
|
|
364
364
|
response.raise_for_status()
|
|
365
365
|
except httpx.HTTPError as exc:
|
|
366
|
-
raise
|
|
366
|
+
raise WeComServerNetworkError(f"POST 请求失败: {exc}", exc) from exc
|
|
367
367
|
return response.json()
|
|
368
368
|
|
|
369
369
|
async def async_post_files(
|
|
@@ -373,5 +373,5 @@ class AsyncWeComServerClient(_BaseServerClient):
|
|
|
373
373
|
response = await self._client.post(url, params=params, files=files)
|
|
374
374
|
response.raise_for_status()
|
|
375
375
|
except httpx.HTTPError as exc:
|
|
376
|
-
raise
|
|
376
|
+
raise WeComServerNetworkError(f"文件上传失败: {exc}", exc) from exc
|
|
377
377
|
return response.json()
|