py-wecom-toolkit 4.0.2__tar.gz → 4.0.4__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.
Files changed (24) hide show
  1. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/PKG-INFO +10 -10
  2. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/README.md +7 -7
  3. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/cache.py +7 -7
  4. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/client.py +13 -13
  5. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/material/client.py +6 -6
  6. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/message/client.py +2 -2
  7. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/pyproject.toml +3 -3
  8. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/.gitignore +0 -0
  9. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/LICENSE +0 -0
  10. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/__init__.py +0 -0
  11. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/py.typed +0 -0
  12. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/__init__.py +0 -0
  13. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/exception.py +0 -0
  14. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/material/__init__.py +0 -0
  15. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/material/msgtype.py +0 -0
  16. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/material/response.py +0 -0
  17. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/message/__init__.py +0 -0
  18. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/message/msgtype.py +0 -0
  19. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/server/response.py +0 -0
  20. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/webhook/__init__.py +0 -0
  21. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/webhook/client.py +0 -0
  22. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/webhook/exception.py +0 -0
  23. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/webhook/msgtype.py +0 -0
  24. {py_wecom_toolkit-4.0.2 → py_wecom_toolkit-4.0.4}/py_wecom_toolkit/webhook/response.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: py_wecom_toolkit
3
- Version: 4.0.2
3
+ Version: 4.0.4
4
4
  Summary: Enterprise WeChat (WeCom) API toolkit for Python / 企业微信(WeCom)API 工具包
5
- Project-URL: homepage, https://gitee.com/guolei19850528/py_wecom_toolkit
6
- Project-URL: repository, https://gitee.com/guolei19850528/py_wecom_toolkit
5
+ Project-URL: HomePage, https://gitee.com/guolei19850528/py_wecom_toolkit
6
+ Project-URL: Repository, https://gitee.com/guolei19850528/py_wecom_toolkit
7
7
  Author-email: 郭磊 <174000902@qq.com>
8
8
  License: MIT
9
9
  License-File: LICENSE
@@ -58,7 +58,7 @@ Description-Content-Type: text/markdown
58
58
 
59
59
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
60
60
 
61
- [中文文档](readme.md) | [English Documentation](readme.en.md)
61
+ [中文文档](README.md) | [English Documentation](README.en.md)
62
62
 
63
63
  ## 📄 文档
64
64
 
@@ -88,7 +88,7 @@ py_wecom_toolkit/
88
88
  27: │ │ │ └── AsyncClient # 异步客户端
89
89
  29: │ │ ├── exception.py # 异常类定义(Error, ConfigError, NetworkError)
90
90
  30: │ │ ├── response.py # 响应模型(BaseResponse, AccessTokenResponse)
91
- 31: │ │ ├── cache.py # 缓存管理(TokenCache, MemoryCache, DiskCache, RedisCache, build_cache_key)
91
+ 31: │ │ ├── cache.py # 缓存管理(AccessTokenCache, AccessTokenMemoryCache, AccessTokenDiskcacheCache, AccessTokenRedisCache, build_access_token_cache_key)
92
92
  32: │ │ ├── message/ # 消息发送子模块
93
93
  33: │ │ │ ├── __init__.py
94
94
  34: │ │ │ ├── client.py # WeCom 消息客户端(同步/异步)
@@ -134,7 +134,7 @@ py_wecom_toolkit/
134
134
  | `server/client.py` | 企业微信 access_token 获取客户端,支持同步和异步调用,自动缓存 access_token |
135
135
  | `server/exception.py` | 定义基础异常类 `Error`、`ConfigError`、`NetworkError` |
136
136
  | `server/response.py` | 定义响应模型 `BaseResponse`、`AccessTokenResponse`,支持 `ok` 属性判断 |
137
- | `server/cache.py` | 缓存抽象层,支持内存缓存(`MemoryCache`)、磁盘缓存(`DiskCache`)、Redis 缓存(`RedisCache`) |
137
+ | `server/cache.py` | 缓存抽象层,支持内存缓存(`AccessTokenMemoryCache`)、磁盘缓存(`AccessTokenDiskcacheCache`)、Redis 缓存(`AccessTokenRedisCache`) |
138
138
  | `server/message/client.py` | 企业微信应用消息客户端,支持文本、markdown、图片、图文、文件、语音、模版卡片等消息类型 |
139
139
  | `server/message/msgtype.py` | 消息类型定义,支持 text、markdown、markdown_v2、image、news、file、voice、template_card |
140
140
  | `server/material/client.py` | 素材管理客户端,支持上传临时素材、上传图片、下载素材 |
@@ -166,10 +166,10 @@ uv add py_wecom_toolkit
166
166
  pip install py_wecom_toolkit
167
167
  ```
168
168
 
169
- ### 方式三:从源码安装
169
+ ### 方式三:从源码安装(dev 分支)
170
170
 
171
171
  ```bash
172
- git clone https://gitee.com/guolei19850528/py_wecom_toolkit.git
172
+ git clone -b dev https://gitee.com/guolei19850528/py_wecom_toolkit.git
173
173
  cd py_wecom_toolkit
174
174
  uv sync --all-groups
175
175
  ```
@@ -194,7 +194,7 @@ from py_wecom_toolkit.server.response import AccessTokenResponse
194
194
 
195
195
  # 初始化客户端
196
196
  with Client(corpid=CORP_ID, corpsecret=CORP_SECRET) as client:
197
- resp: AccessTokenResponse = client.get_token()
197
+ resp: AccessTokenResponse = client.get_access_token()
198
198
  if resp.ok:
199
199
  print(f"access_token: {resp.access_token}")
200
200
  print(f"expires_in: {resp.expires_in} 秒")
@@ -211,7 +211,7 @@ from py_wecom_toolkit.server.response import AccessTokenResponse
211
211
 
212
212
  async def main():
213
213
  async with AsyncClient(corpid=CORP_ID, corpsecret=CORP_SECRET) as client:
214
- resp: AccessTokenResponse = await client.get_token()
214
+ resp: AccessTokenResponse = await client.get_access_token()
215
215
  if resp.ok:
216
216
  print(f"access_token: {resp.access_token}")
217
217
  print(f"expires_in: {resp.expires_in} 秒")
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- [中文文档](readme.md) | [English Documentation](readme.en.md)
5
+ [中文文档](README.md) | [English Documentation](README.en.md)
6
6
 
7
7
  ## 📄 文档
8
8
 
@@ -32,7 +32,7 @@ py_wecom_toolkit/
32
32
  27: │ │ │ └── AsyncClient # 异步客户端
33
33
  29: │ │ ├── exception.py # 异常类定义(Error, ConfigError, NetworkError)
34
34
  30: │ │ ├── response.py # 响应模型(BaseResponse, AccessTokenResponse)
35
- 31: │ │ ├── cache.py # 缓存管理(TokenCache, MemoryCache, DiskCache, RedisCache, build_cache_key)
35
+ 31: │ │ ├── cache.py # 缓存管理(AccessTokenCache, AccessTokenMemoryCache, AccessTokenDiskcacheCache, AccessTokenRedisCache, build_access_token_cache_key)
36
36
  32: │ │ ├── message/ # 消息发送子模块
37
37
  33: │ │ │ ├── __init__.py
38
38
  34: │ │ │ ├── client.py # WeCom 消息客户端(同步/异步)
@@ -78,7 +78,7 @@ py_wecom_toolkit/
78
78
  | `server/client.py` | 企业微信 access_token 获取客户端,支持同步和异步调用,自动缓存 access_token |
79
79
  | `server/exception.py` | 定义基础异常类 `Error`、`ConfigError`、`NetworkError` |
80
80
  | `server/response.py` | 定义响应模型 `BaseResponse`、`AccessTokenResponse`,支持 `ok` 属性判断 |
81
- | `server/cache.py` | 缓存抽象层,支持内存缓存(`MemoryCache`)、磁盘缓存(`DiskCache`)、Redis 缓存(`RedisCache`) |
81
+ | `server/cache.py` | 缓存抽象层,支持内存缓存(`AccessTokenMemoryCache`)、磁盘缓存(`AccessTokenDiskcacheCache`)、Redis 缓存(`AccessTokenRedisCache`) |
82
82
  | `server/message/client.py` | 企业微信应用消息客户端,支持文本、markdown、图片、图文、文件、语音、模版卡片等消息类型 |
83
83
  | `server/message/msgtype.py` | 消息类型定义,支持 text、markdown、markdown_v2、image、news、file、voice、template_card |
84
84
  | `server/material/client.py` | 素材管理客户端,支持上传临时素材、上传图片、下载素材 |
@@ -110,10 +110,10 @@ uv add py_wecom_toolkit
110
110
  pip install py_wecom_toolkit
111
111
  ```
112
112
 
113
- ### 方式三:从源码安装
113
+ ### 方式三:从源码安装(dev 分支)
114
114
 
115
115
  ```bash
116
- git clone https://gitee.com/guolei19850528/py_wecom_toolkit.git
116
+ git clone -b dev https://gitee.com/guolei19850528/py_wecom_toolkit.git
117
117
  cd py_wecom_toolkit
118
118
  uv sync --all-groups
119
119
  ```
@@ -138,7 +138,7 @@ from py_wecom_toolkit.server.response import AccessTokenResponse
138
138
 
139
139
  # 初始化客户端
140
140
  with Client(corpid=CORP_ID, corpsecret=CORP_SECRET) as client:
141
- resp: AccessTokenResponse = client.get_token()
141
+ resp: AccessTokenResponse = client.get_access_token()
142
142
  if resp.ok:
143
143
  print(f"access_token: {resp.access_token}")
144
144
  print(f"expires_in: {resp.expires_in} 秒")
@@ -155,7 +155,7 @@ from py_wecom_toolkit.server.response import AccessTokenResponse
155
155
 
156
156
  async def main():
157
157
  async with AsyncClient(corpid=CORP_ID, corpsecret=CORP_SECRET) as client:
158
- resp: AccessTokenResponse = await client.get_token()
158
+ resp: AccessTokenResponse = await client.get_access_token()
159
159
  if resp.ok:
160
160
  print(f"access_token: {resp.access_token}")
161
161
  print(f"expires_in: {resp.expires_in} 秒")
@@ -5,18 +5,18 @@ import time
5
5
  from abc import ABC, abstractmethod
6
6
  from typing import Optional
7
7
 
8
- CACHE_KEY_PREFIX = "py_wecom_toolkit:server:access_token"
8
+ ACCESS_TOKEN_CACHE_KEY_PREFIX = "py_wecom_toolkit:server:access_token"
9
9
 
10
10
 
11
- def build_cache_key(corpid: str) -> str:
11
+ def build_access_token_cache_key(corpid: str) -> str:
12
12
  """构造 access_token 缓存 key。
13
13
 
14
14
  格式: py_wecom_toolkit:server:access_token:{corpid}
15
15
  """
16
- return f"{CACHE_KEY_PREFIX}:{corpid}"
16
+ return f"{ACCESS_TOKEN_CACHE_KEY_PREFIX}:{corpid}"
17
17
 
18
18
 
19
- class TokenCache(ABC):
19
+ class AccessTokenCache(ABC):
20
20
  """access_token 缓存抽象基类。"""
21
21
 
22
22
  @abstractmethod
@@ -28,7 +28,7 @@ class TokenCache(ABC):
28
28
  """设置缓存值,ttl 为秒。"""
29
29
 
30
30
 
31
- class MemoryCache(TokenCache):
31
+ class AccessTokenMemoryCache(AccessTokenCache):
32
32
  """内存缓存实现(默认,不依赖第三方库)。"""
33
33
 
34
34
  def __init__(self) -> None:
@@ -48,7 +48,7 @@ class MemoryCache(TokenCache):
48
48
  self._store[key] = (value, time.time() + ttl)
49
49
 
50
50
 
51
- class DiskCache(TokenCache):
51
+ class AccessTokenDiskcacheCache(AccessTokenCache):
52
52
  """基于 diskcache 的缓存实现。"""
53
53
 
54
54
  def __init__(self, directory: str = ".cache/py_wecom_toolkit") -> None:
@@ -63,7 +63,7 @@ class DiskCache(TokenCache):
63
63
  self._cache.set(key, value, expire=ttl)
64
64
 
65
65
 
66
- class RedisCache(TokenCache):
66
+ class AccessTokenRedisCache(AccessTokenCache):
67
67
  """基于 redis 的缓存实现。"""
68
68
 
69
69
  def __init__(
@@ -8,7 +8,7 @@ import httpx
8
8
 
9
9
  from .exception import ConfigError, NetworkError
10
10
  from .response import AccessTokenResponse
11
- from .cache import TokenCache, DiskCache, build_cache_key
11
+ from .cache import AccessTokenCache, AccessTokenDiskcacheCache, build_access_token_cache_key
12
12
 
13
13
 
14
14
  class Client:
@@ -35,7 +35,7 @@ class Client:
35
35
  corpid: str,
36
36
  corpsecret: str,
37
37
  *,
38
- cache: Optional[TokenCache] = None,
38
+ cache: Optional[AccessTokenCache] = None,
39
39
  base_url: str = "https://qyapi.weixin.qq.com",
40
40
  timeout: float = 30.0,
41
41
  **httpx_kwargs: Any,
@@ -46,7 +46,7 @@ class Client:
46
46
  raise ConfigError("corpsecret is required")
47
47
  self.corpid = corpid
48
48
  self.corpsecret = corpsecret
49
- self.cache = cache or DiskCache()
49
+ self.cache = cache or AccessTokenDiskcacheCache()
50
50
  self.base_url = base_url.rstrip("/")
51
51
  self.timeout = timeout
52
52
  self._client = httpx.Client(
@@ -70,9 +70,9 @@ class Client:
70
70
  self._client.close()
71
71
 
72
72
  def _cache_key(self) -> str:
73
- return build_cache_key(self.corpid)
73
+ return build_access_token_cache_key(self.corpid)
74
74
 
75
- def get_token(self, force_refresh: bool = False) -> AccessTokenResponse:
75
+ def get_access_token(self, force_refresh: bool = False) -> AccessTokenResponse:
76
76
  """获取 access_token。
77
77
 
78
78
  优先从缓存读取,缓存未命中或 force_refresh 为 True 时重新获取。
@@ -100,12 +100,12 @@ class Client:
100
100
  expires_in=self._get_ttl(),
101
101
  )
102
102
 
103
- response = self._fetch_token()
103
+ response = self._fetch_access_token()
104
104
  if response.ok:
105
105
  self.cache.set(cache_key, response.access_token, ttl=self._get_ttl())
106
106
  return response
107
107
 
108
- def _fetch_token(self) -> AccessTokenResponse:
108
+ def _fetch_access_token(self) -> AccessTokenResponse:
109
109
  resp = self._client.get(
110
110
  "/cgi-bin/gettoken",
111
111
  params={"corpid": self.corpid, "corpsecret": self.corpsecret},
@@ -131,7 +131,7 @@ class AsyncClient:
131
131
  corpid: str,
132
132
  corpsecret: str,
133
133
  *,
134
- cache: Optional[TokenCache] = None,
134
+ cache: Optional[AccessTokenCache] = None,
135
135
  base_url: str = "https://qyapi.weixin.qq.com",
136
136
  timeout: float = 30.0,
137
137
  **httpx_kwargs: Any,
@@ -142,7 +142,7 @@ class AsyncClient:
142
142
  raise ConfigError("corpsecret is required")
143
143
  self.corpid = corpid
144
144
  self.corpsecret = corpsecret
145
- self.cache = cache or DiskCache()
145
+ self.cache = cache or AccessTokenDiskcacheCache()
146
146
  self.base_url = base_url.rstrip("/")
147
147
  self.timeout = timeout
148
148
  self._client = httpx.AsyncClient(
@@ -166,9 +166,9 @@ class AsyncClient:
166
166
  await self._client.aclose()
167
167
 
168
168
  def _cache_key(self) -> str:
169
- return build_cache_key(self.corpid)
169
+ return build_access_token_cache_key(self.corpid)
170
170
 
171
- async def get_token(self, force_refresh: bool = False) -> AccessTokenResponse:
171
+ async def get_access_token(self, force_refresh: bool = False) -> AccessTokenResponse:
172
172
  """获取 access_token(异步)。
173
173
 
174
174
  优先从缓存读取,缓存未命中或 force_refresh 为 True 时重新获取。
@@ -196,12 +196,12 @@ class AsyncClient:
196
196
  expires_in=self._get_ttl(),
197
197
  )
198
198
 
199
- response = await self._fetch_token()
199
+ response = await self._fetch_access_token()
200
200
  if response.ok:
201
201
  self.cache.set(cache_key, response.access_token, ttl=self._get_ttl())
202
202
  return response
203
203
 
204
- async def _fetch_token(self) -> AccessTokenResponse:
204
+ async def _fetch_access_token(self) -> AccessTokenResponse:
205
205
  resp = await self._client.get(
206
206
  "/cgi-bin/gettoken",
207
207
  params={"corpid": self.corpid, "corpsecret": self.corpsecret},
@@ -80,7 +80,7 @@ class Client(BaseClient):
80
80
  NetworkError
81
81
  当网络请求失败时抛出。
82
82
  """
83
- token_response = self.get_token()
83
+ token_response = self.get_access_token()
84
84
  if not token_response.ok:
85
85
  raise ConfigError(
86
86
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -138,7 +138,7 @@ class Client(BaseClient):
138
138
  NetworkError
139
139
  当网络请求失败时抛出。
140
140
  """
141
- token_response = self.get_token()
141
+ token_response = self.get_access_token()
142
142
  if not token_response.ok:
143
143
  raise ConfigError(
144
144
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -190,7 +190,7 @@ class Client(BaseClient):
190
190
  NetworkError
191
191
  当网络请求失败时抛出。
192
192
  """
193
- token_response = self.get_token()
193
+ token_response = self.get_access_token()
194
194
  if not token_response.ok:
195
195
  raise ConfigError(
196
196
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -283,7 +283,7 @@ class AsyncClient(BaseAsyncClient):
283
283
  NetworkError
284
284
  当网络请求失败时抛出。
285
285
  """
286
- token_response = await self.get_token()
286
+ token_response = await self.get_access_token()
287
287
  if not token_response.ok:
288
288
  raise ConfigError(
289
289
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -339,7 +339,7 @@ class AsyncClient(BaseAsyncClient):
339
339
  NetworkError
340
340
  当网络请求失败时抛出。
341
341
  """
342
- token_response = await self.get_token()
342
+ token_response = await self.get_access_token()
343
343
  if not token_response.ok:
344
344
  raise ConfigError(
345
345
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -391,7 +391,7 @@ class AsyncClient(BaseAsyncClient):
391
391
  NetworkError
392
392
  当网络请求失败时抛出。
393
393
  """
394
- token_response = await self.get_token()
394
+ token_response = await self.get_access_token()
395
395
  if not token_response.ok:
396
396
  raise ConfigError(
397
397
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -78,7 +78,7 @@ class Client(BaseClient):
78
78
  if resolved_agentid is None:
79
79
  raise ConfigError("agentid is required")
80
80
 
81
- token_response = self.get_token()
81
+ token_response = self.get_access_token()
82
82
  if not token_response.ok:
83
83
  raise ConfigError(
84
84
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -161,7 +161,7 @@ class AsyncClient(BaseAsyncClient):
161
161
  if resolved_agentid is None:
162
162
  raise ConfigError("agentid is required")
163
163
 
164
- token_response = await self.get_token()
164
+ token_response = await self.get_access_token()
165
165
  if not token_response.ok:
166
166
  raise ConfigError(
167
167
  f"获取 access_token 失败: errcode={token_response.errcode}, "
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "py_wecom_toolkit"
7
- version = "4.0.2"
7
+ version = "4.0.4"
8
8
  description = "Enterprise WeChat (WeCom) API toolkit for Python / 企业微信(WeCom)API 工具包"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -46,8 +46,8 @@ dependencies = [
46
46
  ]
47
47
 
48
48
  [project.urls]
49
- homepage = "https://gitee.com/guolei19850528/py_wecom_toolkit"
50
- repository = "https://gitee.com/guolei19850528/py_wecom_toolkit"
49
+ HomePage = "https://gitee.com/guolei19850528/py_wecom_toolkit"
50
+ Repository = "https://gitee.com/guolei19850528/py_wecom_toolkit"
51
51
 
52
52
  [project.optional-dependencies]
53
53
  dev = [