py-wisharetec-toolkit 1.0.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 郭磊
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.4
2
+ Name: py-wisharetec-toolkit
3
+ Version: 1.0.0
4
+ Summary: Wisharetec SaaS 系统的 Python 客户端库,提供同步和异步接口调用能力。
5
+ Author-email: Guolei <174000902@qq.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 郭磊
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://gitee.com/guolei19850528/py_wisharetec_toolkit
29
+ Project-URL: Repository, https://gitee.com/guolei19850528/py_wisharetec_toolkit.git
30
+ Keywords: wisharetec,python,client,api,wisharetec saas,saas
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Operating System :: OS Independent
40
+ Requires-Python: >=3.10
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: httpx>=0.27.0
44
+ Requires-Dist: pydantic>=2.0
45
+ Requires-Dist: jsonpath-ng>=1.5.3
46
+ Requires-Dist: jsonschema>=4.21.0
47
+ Requires-Dist: diskcache>=5.6.3
48
+ Requires-Dist: redis>=4.6.0
49
+ Requires-Dist: py-httpx-toolkit>=1.0.0
50
+ Provides-Extra: dev
51
+ Requires-Dist: pytest>=7.0; extra == "dev"
52
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
53
+ Requires-Dist: setuptools>=61.0; extra == "dev"
54
+ Requires-Dist: twine>=4.0; extra == "dev"
55
+ Dynamic: license-file
56
+
57
+ # py-wisharetec-toolkit
58
+
59
+ Wisharetec SaaS 系统的 Python 客户端库,提供同步和异步接口调用能力。
60
+
61
+ ## 功能特性
62
+
63
+ - 封装 SaaS 系统的认证机制,包括登录、令牌刷新和令牌缓存
64
+ - 提供同步和异步两种 HTTP 请求模式
65
+ - 集成 JSON Schema 校验和 JSONPath 查询工具
66
+ - 支持 diskcache 和 Redis 两种缓存后端
67
+
68
+ ## 安装
69
+
70
+ ### 使用 uv(推荐)
71
+
72
+ ```bash
73
+ uv add py-wisharetec-toolkit
74
+ ```
75
+
76
+ ### 使用 pip
77
+
78
+ ```bash
79
+ pip install py-wisharetec-toolkit
80
+ ```
81
+
82
+ ## 依赖包
83
+
84
+ | 依赖包 | 版本要求 | 说明 |
85
+ |--------|----------|------|
86
+ | httpx | >=0.27.0 | HTTP 客户端库,支持同步和异步请求 |
87
+ | pydantic | >=2.0 | 数据验证和序列化 |
88
+ | jsonpath-ng | >=1.5.3 | JSONPath 查询工具 |
89
+ | jsonschema | >=4.21.0 | JSON Schema 校验 |
90
+ | diskcache | >=5.6.3 | 本地磁盘缓存 |
91
+ | redis | >=4.6.0 | Redis 缓存支持 |
92
+ | py-httpx-toolkit | >=1.0.0 | HTTP 请求工具封装 |
93
+
94
+ ## API 说明
95
+
96
+ ### Saas 类
97
+
98
+ #### 初始化
99
+
100
+ ```python
101
+ from py_wisharetec_toolkit.saas import Saas
102
+
103
+ saas = Saas(
104
+ base_url="https://saas.wisharetec.com/",
105
+ account="your_account",
106
+ password="your_password",
107
+ cache_config={
108
+ "instance": None, # diskcache.Cache 或 redis.Redis 实例
109
+ "key": "py_wisharetec_saas_account",
110
+ "expire": 7100,
111
+ },
112
+ client_kwargs={
113
+ "timeout": 60,
114
+ "verify": False,
115
+ }
116
+ )
117
+ ```
118
+
119
+ #### 同步方法
120
+
121
+ | 方法 | 说明 |
122
+ |------|------|
123
+ | `login()` | 用户登录,获取认证 Token |
124
+ | `refresh_token()` | 智能刷新 Token(支持缓存) |
125
+ | `query_space_manage_tree()` | 查询空间管理树结构 |
126
+ | `request_with_token()` | 发送带授权头的请求 |
127
+
128
+ #### 异步方法
129
+
130
+ | 方法 | 说明 |
131
+ |------|------|
132
+ | `async_login()` | 异步用户登录 |
133
+ | `async_refresh_token()` | 异步智能刷新 Token |
134
+ | `async_query_space_manage_tree()` | 异步查询空间管理树 |
135
+ | `async_request_with_token()` | 异步发送带授权头的请求 |
136
+
137
+ ## utils 工具函数
138
+
139
+ ### json_find_first
140
+
141
+ 使用 JSONPath 表达式从 JSON 数据中查找第一个匹配项。
142
+
143
+ ```python
144
+ from py_wisharetec_toolkit.saas.utils import json_find_first
145
+
146
+ data = {"userInfoV": {"id": "123"}}
147
+ result = json_find_first("$.userInfoV.id", data)
148
+ # 返回: "123"
149
+ ```
150
+
151
+ ### json_is_valid
152
+
153
+ 校验 JSON 数据是否符合指定的 JSON Schema。
154
+
155
+ ```python
156
+ from py_wisharetec_toolkit.saas.utils import json_is_valid
157
+
158
+ schema = {
159
+ "type": "object",
160
+ "properties": {"id": {"type": "string"}},
161
+ "required": ["id"]
162
+ }
163
+ data = {"id": "123"}
164
+ result = json_is_valid(schema, data)
165
+ # 返回: True
166
+ ```
167
+
168
+ ## 使用示例
169
+
170
+ ### 同步方式
171
+
172
+ ```python
173
+ from py_wisharetec_toolkit.saas import Saas
174
+
175
+ saas = Saas(
176
+ account="test",
177
+ password="password"
178
+ )
179
+
180
+ # 登录获取 Token
181
+ saas.login()
182
+
183
+ # 发送请求
184
+ response = saas.request_with_token(
185
+ method="GET",
186
+ url="/api/data/list"
187
+ )
188
+ print(response.json())
189
+ ```
190
+
191
+ ### 异步方式
192
+
193
+ ```python
194
+ import asyncio
195
+ from py_wisharetec_toolkit.saas import Saas
196
+
197
+ async def main():
198
+ saas = Saas(
199
+ account="test",
200
+ password="password"
201
+ )
202
+
203
+ # 异步登录
204
+ await saas.async_login()
205
+
206
+ # 异步发送请求
207
+ response = await saas.async_request_with_token(
208
+ method="GET",
209
+ url="/api/data/list"
210
+ )
211
+ print(response.json())
212
+
213
+ asyncio.run(main())
214
+ ```
215
+
216
+ ### 使用缓存
217
+
218
+ ```python
219
+ import diskcache
220
+ from py_wisharetec_toolkit.saas import Saas
221
+
222
+ cache = diskcache.Cache("./cache")
223
+
224
+ saas = Saas(
225
+ account="test",
226
+ password="password",
227
+ cache_config={
228
+ "instance": cache,
229
+ "key": "saas_token",
230
+ "expire": 7100
231
+ }
232
+ )
233
+
234
+ # 自动从缓存获取或刷新 Token
235
+ saas.refresh_token()
236
+ ```
237
+
238
+ ## 作者
239
+
240
+ **Guolei**
241
+
242
+ - 邮箱: 174000902@qq.com
243
+
244
+ ## 项目主页
245
+
246
+ - **Gitee**: [https://gitee.com/guolei19850528/py_wisharetec_toolkit](https://gitee.com/guolei19850528/py_wisharetec_toolkit)
247
+
248
+ ## 许可证
249
+
250
+ MIT License
@@ -0,0 +1,194 @@
1
+ # py-wisharetec-toolkit
2
+
3
+ Wisharetec SaaS 系统的 Python 客户端库,提供同步和异步接口调用能力。
4
+
5
+ ## 功能特性
6
+
7
+ - 封装 SaaS 系统的认证机制,包括登录、令牌刷新和令牌缓存
8
+ - 提供同步和异步两种 HTTP 请求模式
9
+ - 集成 JSON Schema 校验和 JSONPath 查询工具
10
+ - 支持 diskcache 和 Redis 两种缓存后端
11
+
12
+ ## 安装
13
+
14
+ ### 使用 uv(推荐)
15
+
16
+ ```bash
17
+ uv add py-wisharetec-toolkit
18
+ ```
19
+
20
+ ### 使用 pip
21
+
22
+ ```bash
23
+ pip install py-wisharetec-toolkit
24
+ ```
25
+
26
+ ## 依赖包
27
+
28
+ | 依赖包 | 版本要求 | 说明 |
29
+ |--------|----------|------|
30
+ | httpx | >=0.27.0 | HTTP 客户端库,支持同步和异步请求 |
31
+ | pydantic | >=2.0 | 数据验证和序列化 |
32
+ | jsonpath-ng | >=1.5.3 | JSONPath 查询工具 |
33
+ | jsonschema | >=4.21.0 | JSON Schema 校验 |
34
+ | diskcache | >=5.6.3 | 本地磁盘缓存 |
35
+ | redis | >=4.6.0 | Redis 缓存支持 |
36
+ | py-httpx-toolkit | >=1.0.0 | HTTP 请求工具封装 |
37
+
38
+ ## API 说明
39
+
40
+ ### Saas 类
41
+
42
+ #### 初始化
43
+
44
+ ```python
45
+ from py_wisharetec_toolkit.saas import Saas
46
+
47
+ saas = Saas(
48
+ base_url="https://saas.wisharetec.com/",
49
+ account="your_account",
50
+ password="your_password",
51
+ cache_config={
52
+ "instance": None, # diskcache.Cache 或 redis.Redis 实例
53
+ "key": "py_wisharetec_saas_account",
54
+ "expire": 7100,
55
+ },
56
+ client_kwargs={
57
+ "timeout": 60,
58
+ "verify": False,
59
+ }
60
+ )
61
+ ```
62
+
63
+ #### 同步方法
64
+
65
+ | 方法 | 说明 |
66
+ |------|------|
67
+ | `login()` | 用户登录,获取认证 Token |
68
+ | `refresh_token()` | 智能刷新 Token(支持缓存) |
69
+ | `query_space_manage_tree()` | 查询空间管理树结构 |
70
+ | `request_with_token()` | 发送带授权头的请求 |
71
+
72
+ #### 异步方法
73
+
74
+ | 方法 | 说明 |
75
+ |------|------|
76
+ | `async_login()` | 异步用户登录 |
77
+ | `async_refresh_token()` | 异步智能刷新 Token |
78
+ | `async_query_space_manage_tree()` | 异步查询空间管理树 |
79
+ | `async_request_with_token()` | 异步发送带授权头的请求 |
80
+
81
+ ## utils 工具函数
82
+
83
+ ### json_find_first
84
+
85
+ 使用 JSONPath 表达式从 JSON 数据中查找第一个匹配项。
86
+
87
+ ```python
88
+ from py_wisharetec_toolkit.saas.utils import json_find_first
89
+
90
+ data = {"userInfoV": {"id": "123"}}
91
+ result = json_find_first("$.userInfoV.id", data)
92
+ # 返回: "123"
93
+ ```
94
+
95
+ ### json_is_valid
96
+
97
+ 校验 JSON 数据是否符合指定的 JSON Schema。
98
+
99
+ ```python
100
+ from py_wisharetec_toolkit.saas.utils import json_is_valid
101
+
102
+ schema = {
103
+ "type": "object",
104
+ "properties": {"id": {"type": "string"}},
105
+ "required": ["id"]
106
+ }
107
+ data = {"id": "123"}
108
+ result = json_is_valid(schema, data)
109
+ # 返回: True
110
+ ```
111
+
112
+ ## 使用示例
113
+
114
+ ### 同步方式
115
+
116
+ ```python
117
+ from py_wisharetec_toolkit.saas import Saas
118
+
119
+ saas = Saas(
120
+ account="test",
121
+ password="password"
122
+ )
123
+
124
+ # 登录获取 Token
125
+ saas.login()
126
+
127
+ # 发送请求
128
+ response = saas.request_with_token(
129
+ method="GET",
130
+ url="/api/data/list"
131
+ )
132
+ print(response.json())
133
+ ```
134
+
135
+ ### 异步方式
136
+
137
+ ```python
138
+ import asyncio
139
+ from py_wisharetec_toolkit.saas import Saas
140
+
141
+ async def main():
142
+ saas = Saas(
143
+ account="test",
144
+ password="password"
145
+ )
146
+
147
+ # 异步登录
148
+ await saas.async_login()
149
+
150
+ # 异步发送请求
151
+ response = await saas.async_request_with_token(
152
+ method="GET",
153
+ url="/api/data/list"
154
+ )
155
+ print(response.json())
156
+
157
+ asyncio.run(main())
158
+ ```
159
+
160
+ ### 使用缓存
161
+
162
+ ```python
163
+ import diskcache
164
+ from py_wisharetec_toolkit.saas import Saas
165
+
166
+ cache = diskcache.Cache("./cache")
167
+
168
+ saas = Saas(
169
+ account="test",
170
+ password="password",
171
+ cache_config={
172
+ "instance": cache,
173
+ "key": "saas_token",
174
+ "expire": 7100
175
+ }
176
+ )
177
+
178
+ # 自动从缓存获取或刷新 Token
179
+ saas.refresh_token()
180
+ ```
181
+
182
+ ## 作者
183
+
184
+ **Guolei**
185
+
186
+ - 邮箱: 174000902@qq.com
187
+
188
+ ## 项目主页
189
+
190
+ - **Gitee**: [https://gitee.com/guolei19850528/py_wisharetec_toolkit](https://gitee.com/guolei19850528/py_wisharetec_toolkit)
191
+
192
+ ## 许可证
193
+
194
+ MIT License
@@ -0,0 +1,48 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+ [project]
5
+ name = "py-wisharetec-toolkit"
6
+ version = "1.0.0"
7
+ requires-python = ">=3.10"
8
+ authors = [
9
+ { name = "Guolei", email = "174000902@qq.com" }
10
+ ]
11
+ description = "Wisharetec SaaS 系统的 Python 客户端库,提供同步和异步接口调用能力。"
12
+ keywords = ["wisharetec", "python", "client", "api", "wisharetec saas", "saas"]
13
+ license = { file = "LICENSE" }
14
+ readme = "README.md"
15
+ classifiers = [
16
+ "License :: OSI Approved :: MIT License",
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Operating System :: OS Independent",
25
+ ]
26
+ dependencies = [
27
+ "httpx>=0.27.0",
28
+ "pydantic>=2.0",
29
+ "jsonpath-ng>=1.5.3",
30
+ "jsonschema>=4.21.0",
31
+ "diskcache>=5.6.3",
32
+ "redis>=4.6.0",
33
+ "py-httpx-toolkit>=1.0.0",
34
+ ]
35
+ [project.optional-dependencies]
36
+ dev = [
37
+ "pytest>=7.0",
38
+ "pytest-cov>=4.0",
39
+ "setuptools>=61.0",
40
+ "twine>=4.0",
41
+ ]
42
+
43
+ [project.urls]
44
+ "Homepage" = "https://gitee.com/guolei19850528/py_wisharetec_toolkit"
45
+ "Repository" = "https://gitee.com/guolei19850528/py_wisharetec_toolkit.git"
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ py_wisharetec 包入口模块
5
+
6
+ Wisharetec SaaS 系统的 Python 客户端库,提供同步和异步接口调用能力。
7
+
8
+ 主要功能:
9
+ - 封装 SaaS 系统的认证机制,包括登录、令牌刷新和令牌缓存
10
+ - 提供同步和异步两种 HTTP 请求模式
11
+ - 集成 JSON Schema 校验和 JSONPath 查询工具
12
+ - 支持 diskcache 和 Redis 两种缓存后端
13
+
14
+ 子模块说明:
15
+ - saas: 核心 SaaS 客户端实现,包含 Saas 类和工具函数
16
+ - saas.utils: 工具函数模块,提供 JSON 数据处理相关功能
17
+ """
@@ -0,0 +1,523 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: UTF-8 -*-
3
+ import hashlib
4
+ from typing import Optional, Union
5
+
6
+ import diskcache
7
+ import httpx
8
+ import redis
9
+ from py_httpx_toolkit import Httpx
10
+
11
+ from .utils import json_is_valid
12
+
13
+
14
+ class Saas(Httpx):
15
+ """
16
+ SaaS系统客户端类,继承自Httpx,提供与Wisharetec SaaS平台的交互能力
17
+
18
+ 主要功能包括:
19
+ - 用户登录认证
20
+ - Token管理与自动刷新
21
+ - 请求授权头自动添加
22
+ - 支持同步和异步请求
23
+ - 支持缓存Token(Redis/diskcache)
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ base_url: Optional[str] = "https://saas.wisharetec.com/",
29
+ account: Optional[str] = None,
30
+ password: Optional[str] = None,
31
+ cache_config: Optional[dict] = None,
32
+ client_kwargs: Optional[dict] = None
33
+ ):
34
+ """
35
+ 初始化SaaS客户端
36
+
37
+ :param base_url: SaaS平台基础URL,默认为"https://saas.wisharetec.com/"
38
+ :param account: 用户账号
39
+ :param password: 用户密码(明文,内部会进行MD5加密)
40
+ :param cache_config: 缓存配置字典,支持以下键:
41
+ - instance: 缓存实例(diskcache.Cache或redis.Redis),为None时不使用缓存
42
+ - key: 缓存键名,默认为"py_wisharetec_saas_{account}"
43
+ - expire: 缓存过期时间(秒),默认为7100秒
44
+ :param client_kwargs: httpx客户端配置参数,会覆盖默认配置
45
+ """
46
+ # 处理基础URL,移除末尾斜杠保证URL格式统一
47
+ self.base_url = base_url or "https://saas.wisharetec.com/"
48
+ self.base_url = self.base_url[:-1] if self.base_url.endswith("/") else self.base_url
49
+
50
+ # 存储账号密码(密码在请求时进行MD5加密)
51
+ self.account = account or ""
52
+ self.password = password or ""
53
+
54
+ # 配置缓存参数,使用默认值与用户配置合并
55
+ self.cache_config = cache_config or {}
56
+ self.cache_config = {
57
+ **{
58
+ "instance": None, # 缓存实例
59
+ "key": f"py_wisharetec_saas_{self.account}", # 缓存键
60
+ "expire": 7100, # 过期时间(秒)
61
+ },
62
+ **self.cache_config,
63
+ }
64
+
65
+ # 配置httpx客户端参数,使用默认值与用户配置合并
66
+ self.client_kwargs = client_kwargs or {}
67
+ self.client_kwargs = {
68
+ **{
69
+ "base_url": self.base_url, # 基础URL
70
+ "timeout": 60, # 请求超时时间(秒)
71
+ "verify": False, # 禁用SSL证书验证
72
+ "headers": {
73
+ "client": "co-pc" # 客户端标识
74
+ }
75
+ },
76
+ **self.client_kwargs,
77
+ }
78
+
79
+ # 初始化token为空,需要通过login或refresh_token获取
80
+ self.token = ""
81
+
82
+ def query_space_manage_tree(
83
+ self,
84
+ client: Optional[httpx.Client] = None,
85
+ client_kwargs: Optional[dict] = None,
86
+ **kwargs
87
+ ) -> httpx.Response:
88
+ """
89
+ 查询空间管理树结构
90
+
91
+ 该方法用于获取当前用户有权限访问的空间管理树数据,常用于验证Token是否有效。
92
+ 请求会携带账号和MD5加密后的密码进行身份验证。
93
+
94
+ :param client: 可选的同步httpx.Client实例,若未提供则使用默认客户端
95
+ :param client_kwargs: 可选的客户端配置参数
96
+ :param kwargs: 额外的请求参数,可覆盖默认配置(如method、url、headers等)
97
+ :return: httpx.Response - HTTP响应对象,成功时包含空间管理树数据
98
+ """
99
+ # 处理参数默认值
100
+ client = client or None
101
+ client_kwargs = client_kwargs or {}
102
+ kwargs = kwargs or {}
103
+
104
+ # 构建请求参数,合并默认配置与用户传入的配置
105
+ kwargs = {
106
+ **{
107
+ "method": "GET",
108
+ "url": "/api/space/space/manageTree",
109
+ "headers": {
110
+ "client": "co-pc",
111
+ "authorization": self.token,
112
+ },
113
+ "json": {
114
+ "account": self.account,
115
+ "password": hashlib.md5(self.password.encode("utf-8")).hexdigest(), # 密码MD5加密
116
+ },
117
+ },
118
+ **kwargs,
119
+ }
120
+
121
+ # 调用父类的request方法发送请求
122
+ return self.request(client=client, client_kwargs=client_kwargs, **kwargs)
123
+
124
+ def login(
125
+ self,
126
+ client: Optional[httpx.Client] = None,
127
+ client_kwargs: Optional[dict] = None,
128
+ **kwargs
129
+ ) -> httpx.Response:
130
+ """
131
+ 用户登录SaaS系统
132
+
133
+ 该方法向登录接口发送POST请求,携带账号和MD5加密后的密码进行身份认证。
134
+ 登录成功后,从响应头中提取authorization token并存储在实例中。
135
+
136
+ :param client: 可选的同步httpx.Client实例,若未提供则使用默认客户端
137
+ :param client_kwargs: 可选的客户端配置参数
138
+ :param kwargs: 额外的请求参数,可覆盖默认配置
139
+ :return: httpx.Response - HTTP响应对象
140
+ """
141
+ # 处理参数默认值
142
+ client = client or None
143
+ client_kwargs = client_kwargs or {}
144
+ kwargs = kwargs or {}
145
+
146
+ # 构建登录请求参数
147
+ kwargs = {
148
+ **{
149
+ "method": "POST",
150
+ "url": "/api/user/loginInteractive", # 登录接口路径
151
+ "headers": {
152
+ "client": "co-pc"
153
+ },
154
+ "json": {
155
+ "account": self.account,
156
+ "password": hashlib.md5(self.password.encode("utf-8")).hexdigest(), # 密码MD5加密
157
+ },
158
+ },
159
+ **kwargs,
160
+ }
161
+
162
+ # 发送登录请求
163
+ response = self.request(client=client, client_kwargs=client_kwargs, **kwargs)
164
+
165
+ # 解析响应,提取token
166
+ if response.is_success:
167
+ # 使用JSON Schema校验响应数据结构是否符合预期
168
+ if json_is_valid(
169
+ schema={
170
+ "type": "object",
171
+ "properties": {
172
+ "userLoginV": {
173
+ "type": "object",
174
+ "properties": {
175
+ "userInfoV": {
176
+ "type": "object",
177
+ "properties": {
178
+ "id": {"type": "string", "minLength": 1}
179
+ },
180
+ "required": ["id"]
181
+ },
182
+ },
183
+ "required": ["userInfoV"]
184
+ }
185
+ },
186
+ "required": ["userLoginV"],
187
+ },
188
+ data=response.json(),
189
+ ):
190
+ # 从响应头中获取authorization token
191
+ self.token = response.headers.get("authorization", "")
192
+ else:
193
+ # 响应数据结构不符合预期,清空token
194
+ self.token = ""
195
+
196
+ return response
197
+
198
+ def refresh_token(
199
+ self,
200
+ login_func_kwargs: Optional[dict] = None,
201
+ query_space_manage_tree_func_kwargs: Optional[dict] = None,
202
+ ) -> "Saas":
203
+ """
204
+ 刷新并获取有效的认证Token
205
+
206
+ 该方法实现了智能Token刷新逻辑:
207
+ 1. 如果未配置缓存实例,直接调用login获取新token
208
+ 2. 如果配置了缓存,优先从缓存中读取token
209
+ 3. 缓存中没有token或token无效时,调用login重新获取
210
+ 4. 通过query_space_manage_tree验证token是否有效
211
+ 5. 验证通过后将token存入缓存
212
+
213
+ :param login_func_kwargs: 传递给login方法的额外参数
214
+ :param query_space_manage_tree_func_kwargs: 传递给query_space_manage_tree方法的额外参数
215
+ :return: Saas实例本身,支持链式调用
216
+ """
217
+ # 处理参数默认值
218
+ login_func_kwargs = login_func_kwargs or {}
219
+ query_space_manage_tree_func_kwargs = query_space_manage_tree_func_kwargs or {}
220
+
221
+ # 获取缓存配置
222
+ cache_key = self.cache_config.get("key", f"py_wisharetec_saas_{self.account}")
223
+ cache_expire = self.cache_config.get("expire", 7100)
224
+ cache_instance = self.cache_config.get("instance", None)
225
+
226
+ # 判断是否配置了有效的缓存实例
227
+ if not isinstance(cache_instance, Union[diskcache.Cache, redis.Redis]):
228
+ # 未配置缓存,直接登录获取token
229
+ self.login(**login_func_kwargs)
230
+ else:
231
+ # 从缓存中读取token
232
+ self.token = cache_instance.get(cache_key)
233
+
234
+ # 如果缓存中没有token或token无效,重新登录
235
+ if not isinstance(self.token, str) or not len(self.token):
236
+ self.login(**login_func_kwargs)
237
+
238
+ # 查询空间管理树验证token是否有效
239
+ response_json = self.query_space_manage_tree(**query_space_manage_tree_func_kwargs).json()
240
+
241
+ # 如果token无效,重新登录
242
+ if not json_is_valid(
243
+ schema={
244
+ "type": "array",
245
+ "minItems": 1,
246
+ },
247
+ data=response_json,
248
+ ):
249
+ self.login(**login_func_kwargs)
250
+
251
+ # 如果token有效,将其存入缓存
252
+ if json_is_valid(
253
+ schema={
254
+ "type": "array",
255
+ "minItems": 1,
256
+ },
257
+ data=response_json,
258
+ ):
259
+ if isinstance(cache_instance, diskcache.Cache):
260
+ cache_instance.set(cache_key, self.token, expire=cache_expire)
261
+ elif isinstance(cache_instance, redis.Redis):
262
+ cache_instance.set(cache_key, self.token, ex=cache_expire)
263
+
264
+ return self
265
+
266
+ def request_with_token(
267
+ self,
268
+ client: Optional[httpx.Client] = None,
269
+ client_kwargs: Optional[dict] = None,
270
+ **kwargs
271
+ ) -> httpx.Response:
272
+ """
273
+ 发送请求并自动添加授权头
274
+
275
+ 该方法会在请求头中自动添加client标识和authorization token,
276
+ 确保请求携带有效的身份认证信息。
277
+
278
+ :param client: 可选的同步httpx.Client实例,若未提供则使用默认客户端
279
+ :param client_kwargs: 可选的客户端配置参数
280
+ :param kwargs: 传递给request的额外参数,可覆盖headers配置
281
+ :return: httpx.Response - HTTP响应对象
282
+ """
283
+ # 处理参数默认值
284
+ client = client or None
285
+ client_kwargs = client_kwargs or {}
286
+ kwargs = kwargs or {}
287
+
288
+ # 构建请求头,添加认证信息
289
+ kwargs = {
290
+ "headers": {
291
+ "client": "co-pc", # 客户端标识
292
+ "authorization": self.token, # 认证token
293
+ },
294
+ **kwargs,
295
+ }
296
+
297
+ # 调用父类的request方法发送请求
298
+ return self.request(client=client, client_kwargs=client_kwargs, **kwargs)
299
+
300
+ async def async_query_space_manage_tree(
301
+ self,
302
+ client: Optional[httpx.AsyncClient] = None,
303
+ client_kwargs: Optional[dict] = None,
304
+ **kwargs
305
+ ) -> httpx.Response:
306
+ """
307
+ 异步查询空间管理树结构
308
+
309
+ 该方法用于异步获取当前用户有权限访问的空间管理树数据,常用于验证Token是否有效。
310
+ 请求会携带账号和MD5加密后的密码进行身份验证。
311
+
312
+ :param client: 可选的异步httpx.AsyncClient实例,若未提供则使用默认客户端
313
+ :param client_kwargs: 可选的客户端配置参数
314
+ :param kwargs: 额外的请求参数,可覆盖默认配置
315
+ :return: httpx.Response - HTTP响应对象,成功时包含空间管理树数据
316
+ """
317
+ # 处理参数默认值
318
+ client = client or None
319
+ client_kwargs = client_kwargs or {}
320
+ kwargs = kwargs or {}
321
+
322
+ # 构建请求参数,合并默认配置与用户传入的配置
323
+ kwargs = {
324
+ **{
325
+ "method": "GET",
326
+ "url": "/api/space/space/manageTree",
327
+ "headers": {
328
+ "client": "co-pc",
329
+ "authorization": self.token,
330
+ },
331
+ "json": {
332
+ "account": self.account,
333
+ "password": hashlib.md5(self.password.encode("utf-8")).hexdigest(), # 密码MD5加密
334
+ },
335
+ },
336
+ **kwargs,
337
+ }
338
+
339
+ # 调用异步请求方法,自动添加授权头
340
+ return await self.async_request_with_token(client=client, client_kwargs=client_kwargs, **kwargs)
341
+
342
+ async def async_login(
343
+ self,
344
+ client: Optional[httpx.AsyncClient] = None,
345
+ client_kwargs: Optional[dict] = None,
346
+ **kwargs
347
+ ) -> httpx.Response:
348
+ """
349
+ 异步用户登录SaaS系统
350
+
351
+ 该方法向登录接口异步发送POST请求,携带账号和MD5加密后的密码进行身份认证。
352
+ 登录成功后,从响应头中提取authorization token并存储在实例中。
353
+
354
+ :param client: 可选的异步httpx.AsyncClient实例,若未提供则使用默认客户端
355
+ :param client_kwargs: 可选的客户端配置参数
356
+ :param kwargs: 额外的请求参数,可覆盖默认配置
357
+ :return: httpx.Response - HTTP响应对象
358
+ """
359
+ # 处理参数默认值
360
+ client = client or None
361
+ client_kwargs = client_kwargs or {}
362
+ kwargs = kwargs or {}
363
+
364
+ # 构建登录请求参数
365
+ kwargs = {
366
+ **{
367
+ "method": "POST",
368
+ "url": "/api/user/loginInteractive", # 登录接口路径
369
+ "headers": {
370
+ "client": "co-pc"
371
+ },
372
+ "json": {
373
+ "account": self.account,
374
+ "password": hashlib.md5(self.password.encode("utf-8")).hexdigest(), # 密码MD5加密
375
+ },
376
+ },
377
+ **kwargs,
378
+ }
379
+
380
+ # 发送异步登录请求
381
+ response = await self.async_request_with_token(client=client, client_kwargs=client_kwargs, **kwargs)
382
+
383
+ # 解析响应,提取token
384
+ if response.is_success:
385
+ # 使用JSON Schema校验响应数据结构是否符合预期
386
+ if json_is_valid(
387
+ schema={
388
+ "type": "object",
389
+ "properties": {
390
+ "userLoginV": {
391
+ "type": "object",
392
+ "properties": {
393
+ "userInfoV": {
394
+ "type": "object",
395
+ "properties": {
396
+ "id": {"type": "string", "minLength": 1}
397
+ },
398
+ "required": ["id"]
399
+ },
400
+ },
401
+ "required": ["userInfoV"]
402
+ }
403
+ },
404
+ "required": ["userLoginV"],
405
+ },
406
+ data=response.json(),
407
+ ):
408
+ # 从响应头中获取authorization token
409
+ self.token = response.headers.get("authorization", "")
410
+ else:
411
+ # 响应数据结构不符合预期,清空token
412
+ self.token = ""
413
+
414
+ return response
415
+
416
+ async def async_refresh_token(
417
+ self,
418
+ login_func_kwargs: Optional[dict] = None,
419
+ query_space_manage_tree_func_kwargs: Optional[dict] = None,
420
+ ) -> "Saas":
421
+ """
422
+ 异步刷新并获取有效的认证Token
423
+
424
+ 该方法实现了异步的智能Token刷新逻辑:
425
+ 1. 如果未配置缓存实例,直接调用async_login获取新token
426
+ 2. 如果配置了缓存,优先从缓存中读取token
427
+ 3. 缓存中没有token或token无效时,调用async_login重新获取
428
+ 4. 通过async_query_space_manage_tree验证token是否有效
429
+ 5. 验证通过后将token存入缓存
430
+
431
+ :param login_func_kwargs: 传递给async_login方法的额外参数
432
+ :param query_space_manage_tree_func_kwargs: 传递给async_query_space_manage_tree方法的额外参数
433
+ :return: Saas实例本身,支持链式调用
434
+ """
435
+ # 处理参数默认值
436
+ login_func_kwargs = login_func_kwargs or {}
437
+ query_space_manage_tree_func_kwargs = query_space_manage_tree_func_kwargs or {}
438
+
439
+ # 获取缓存配置
440
+ cache_key = self.cache_config.get("key", f"py_wisharetec_saas_{self.account}")
441
+ cache_expire = self.cache_config.get("expire", 7100)
442
+ cache_instance = self.cache_config.get("instance", None)
443
+
444
+ # 判断是否配置了有效的缓存实例
445
+ if not isinstance(cache_instance, Union[diskcache.Cache, redis.Redis]):
446
+ # 未配置缓存,直接异步登录获取token
447
+ await self.async_login(**login_func_kwargs)
448
+ else:
449
+ # 从缓存中读取token
450
+ self.token = cache_instance.get(cache_key)
451
+
452
+ # 如果缓存中没有token或token无效,重新异步登录
453
+ if not isinstance(self.token, str) or not len(self.token):
454
+ await self.async_login(**login_func_kwargs)
455
+
456
+ # 异步查询空间管理树验证token是否有效
457
+ response = await self.async_query_space_manage_tree(**query_space_manage_tree_func_kwargs)
458
+
459
+ # 如果token无效,重新异步登录
460
+ if not json_is_valid(
461
+ schema={
462
+ "type": "object",
463
+ "properties": {
464
+ "children": {"type": "array", "minItems": 1},
465
+ },
466
+ "required": ["children"],
467
+ },
468
+ data=response.json(),
469
+ ):
470
+ await self.async_login(**login_func_kwargs)
471
+
472
+ # 再次验证token并保存到缓存
473
+ response = await self.async_query_space_manage_tree(**query_space_manage_tree_func_kwargs)
474
+ if json_is_valid(
475
+ schema={
476
+ "type": "object",
477
+ "properties": {
478
+ "children": {"type": "array", "minItems": 1},
479
+ },
480
+ "required": ["children"],
481
+ },
482
+ data=response.json(),
483
+ ):
484
+ if isinstance(cache_instance, diskcache.Cache):
485
+ cache_instance.set(cache_key, self.token, expire=cache_expire)
486
+ elif isinstance(cache_instance, redis.Redis):
487
+ cache_instance.set(cache_key, self.token, ex=cache_expire)
488
+
489
+ return self
490
+
491
+ async def async_request_with_token(
492
+ self,
493
+ client: Optional[httpx.AsyncClient] = None,
494
+ client_kwargs: Optional[dict] = None,
495
+ **kwargs
496
+ ) -> httpx.Response:
497
+ """
498
+ 异步发送请求并自动添加授权头
499
+
500
+ 该方法会在请求头中自动添加client标识和authorization token,
501
+ 确保请求携带有效的身份认证信息。
502
+
503
+ :param client: 可选的异步httpx.AsyncClient实例,若未提供则使用默认客户端
504
+ :param client_kwargs: 可选的客户端配置参数
505
+ :param kwargs: 传递给async_request的额外参数,可覆盖headers配置
506
+ :return: httpx.Response - HTTP响应对象
507
+ """
508
+ # 处理参数默认值
509
+ client = client or None
510
+ client_kwargs = client_kwargs or {}
511
+ kwargs = kwargs or {}
512
+
513
+ # 构建请求头,添加认证信息
514
+ kwargs = {
515
+ "headers": {
516
+ "client": "co-pc", # 客户端标识
517
+ "authorization": self.token, # 认证token
518
+ },
519
+ **kwargs,
520
+ }
521
+
522
+ # 调用父类的async_request方法发送异步请求
523
+ return await self.async_request(client=client, client_kwargs=client_kwargs, **kwargs)
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: UTF-8 -*-
3
+ from datetime import datetime
4
+ from typing import Any, Optional, Union
5
+
6
+ import httpx
7
+ from jsonpath_ng import parse
8
+ from jsonschema.validators import Draft202012Validator
9
+
10
+
11
+ def json_find_first(expression: str, data: Any) -> Any:
12
+ """
13
+ 使用 JSONPath 表达式从 JSON 数据中查找第一个匹配项
14
+
15
+ 该函数使用 jsonpath-ng 库解析 JSONPath 表达式,并从给定的数据中提取第一个匹配的值。
16
+ 常用于从复杂的 JSON 结构中快速定位特定字段。
17
+
18
+ :param expression: JSONPath 表达式,用于指定要查找的数据路径
19
+ 例如: "$.userInfoV.id" 表示查找根节点下的 userInfoV 对象的 id 字段
20
+ :param data: 待查询的 JSON 数据(字典或列表)
21
+ :return: Any - 第一个匹配的值,如果没有匹配项则返回 None
22
+ """
23
+ # 使用 jsonpath-ng 解析表达式并查找所有匹配项
24
+ results = [i.value for i in parse(expression).find(data)]
25
+
26
+ # 检查结果列表是否非空,返回第一个匹配项
27
+ if isinstance(results, list) and len(results) > 0:
28
+ return results[0]
29
+
30
+ # 没有找到匹配项,返回 None
31
+ return None
32
+
33
+
34
+ def json_is_valid(schema: Optional[dict], data: Any) -> bool:
35
+ """
36
+ 校验 JSON 数据是否符合指定的 JSON Schema
37
+
38
+ 该函数使用 JSON Schema Draft 2020-12 规范对数据进行校验,
39
+ 确保数据结构符合预期。常用于 API 响应数据的格式验证。
40
+
41
+ :param schema: JSON Schema 字典,定义了数据应满足的结构约束
42
+ 例如: {"type": "object", "properties": {"id": {"type": "string"}}, "required": ["id"]}
43
+ :param data: 待校验的 JSON 数据(可以是任意类型)
44
+ :return: bool - 校验是否成功,符合 Schema 返回 True,否则返回 False
45
+ """
46
+ # 使用 Draft202012Validator 进行 Schema 校验
47
+ return Draft202012Validator(schema).is_valid(data)
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.4
2
+ Name: py-wisharetec-toolkit
3
+ Version: 1.0.0
4
+ Summary: Wisharetec SaaS 系统的 Python 客户端库,提供同步和异步接口调用能力。
5
+ Author-email: Guolei <174000902@qq.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 郭磊
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://gitee.com/guolei19850528/py_wisharetec_toolkit
29
+ Project-URL: Repository, https://gitee.com/guolei19850528/py_wisharetec_toolkit.git
30
+ Keywords: wisharetec,python,client,api,wisharetec saas,saas
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Operating System :: OS Independent
40
+ Requires-Python: >=3.10
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: httpx>=0.27.0
44
+ Requires-Dist: pydantic>=2.0
45
+ Requires-Dist: jsonpath-ng>=1.5.3
46
+ Requires-Dist: jsonschema>=4.21.0
47
+ Requires-Dist: diskcache>=5.6.3
48
+ Requires-Dist: redis>=4.6.0
49
+ Requires-Dist: py-httpx-toolkit>=1.0.0
50
+ Provides-Extra: dev
51
+ Requires-Dist: pytest>=7.0; extra == "dev"
52
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
53
+ Requires-Dist: setuptools>=61.0; extra == "dev"
54
+ Requires-Dist: twine>=4.0; extra == "dev"
55
+ Dynamic: license-file
56
+
57
+ # py-wisharetec-toolkit
58
+
59
+ Wisharetec SaaS 系统的 Python 客户端库,提供同步和异步接口调用能力。
60
+
61
+ ## 功能特性
62
+
63
+ - 封装 SaaS 系统的认证机制,包括登录、令牌刷新和令牌缓存
64
+ - 提供同步和异步两种 HTTP 请求模式
65
+ - 集成 JSON Schema 校验和 JSONPath 查询工具
66
+ - 支持 diskcache 和 Redis 两种缓存后端
67
+
68
+ ## 安装
69
+
70
+ ### 使用 uv(推荐)
71
+
72
+ ```bash
73
+ uv add py-wisharetec-toolkit
74
+ ```
75
+
76
+ ### 使用 pip
77
+
78
+ ```bash
79
+ pip install py-wisharetec-toolkit
80
+ ```
81
+
82
+ ## 依赖包
83
+
84
+ | 依赖包 | 版本要求 | 说明 |
85
+ |--------|----------|------|
86
+ | httpx | >=0.27.0 | HTTP 客户端库,支持同步和异步请求 |
87
+ | pydantic | >=2.0 | 数据验证和序列化 |
88
+ | jsonpath-ng | >=1.5.3 | JSONPath 查询工具 |
89
+ | jsonschema | >=4.21.0 | JSON Schema 校验 |
90
+ | diskcache | >=5.6.3 | 本地磁盘缓存 |
91
+ | redis | >=4.6.0 | Redis 缓存支持 |
92
+ | py-httpx-toolkit | >=1.0.0 | HTTP 请求工具封装 |
93
+
94
+ ## API 说明
95
+
96
+ ### Saas 类
97
+
98
+ #### 初始化
99
+
100
+ ```python
101
+ from py_wisharetec_toolkit.saas import Saas
102
+
103
+ saas = Saas(
104
+ base_url="https://saas.wisharetec.com/",
105
+ account="your_account",
106
+ password="your_password",
107
+ cache_config={
108
+ "instance": None, # diskcache.Cache 或 redis.Redis 实例
109
+ "key": "py_wisharetec_saas_account",
110
+ "expire": 7100,
111
+ },
112
+ client_kwargs={
113
+ "timeout": 60,
114
+ "verify": False,
115
+ }
116
+ )
117
+ ```
118
+
119
+ #### 同步方法
120
+
121
+ | 方法 | 说明 |
122
+ |------|------|
123
+ | `login()` | 用户登录,获取认证 Token |
124
+ | `refresh_token()` | 智能刷新 Token(支持缓存) |
125
+ | `query_space_manage_tree()` | 查询空间管理树结构 |
126
+ | `request_with_token()` | 发送带授权头的请求 |
127
+
128
+ #### 异步方法
129
+
130
+ | 方法 | 说明 |
131
+ |------|------|
132
+ | `async_login()` | 异步用户登录 |
133
+ | `async_refresh_token()` | 异步智能刷新 Token |
134
+ | `async_query_space_manage_tree()` | 异步查询空间管理树 |
135
+ | `async_request_with_token()` | 异步发送带授权头的请求 |
136
+
137
+ ## utils 工具函数
138
+
139
+ ### json_find_first
140
+
141
+ 使用 JSONPath 表达式从 JSON 数据中查找第一个匹配项。
142
+
143
+ ```python
144
+ from py_wisharetec_toolkit.saas.utils import json_find_first
145
+
146
+ data = {"userInfoV": {"id": "123"}}
147
+ result = json_find_first("$.userInfoV.id", data)
148
+ # 返回: "123"
149
+ ```
150
+
151
+ ### json_is_valid
152
+
153
+ 校验 JSON 数据是否符合指定的 JSON Schema。
154
+
155
+ ```python
156
+ from py_wisharetec_toolkit.saas.utils import json_is_valid
157
+
158
+ schema = {
159
+ "type": "object",
160
+ "properties": {"id": {"type": "string"}},
161
+ "required": ["id"]
162
+ }
163
+ data = {"id": "123"}
164
+ result = json_is_valid(schema, data)
165
+ # 返回: True
166
+ ```
167
+
168
+ ## 使用示例
169
+
170
+ ### 同步方式
171
+
172
+ ```python
173
+ from py_wisharetec_toolkit.saas import Saas
174
+
175
+ saas = Saas(
176
+ account="test",
177
+ password="password"
178
+ )
179
+
180
+ # 登录获取 Token
181
+ saas.login()
182
+
183
+ # 发送请求
184
+ response = saas.request_with_token(
185
+ method="GET",
186
+ url="/api/data/list"
187
+ )
188
+ print(response.json())
189
+ ```
190
+
191
+ ### 异步方式
192
+
193
+ ```python
194
+ import asyncio
195
+ from py_wisharetec_toolkit.saas import Saas
196
+
197
+ async def main():
198
+ saas = Saas(
199
+ account="test",
200
+ password="password"
201
+ )
202
+
203
+ # 异步登录
204
+ await saas.async_login()
205
+
206
+ # 异步发送请求
207
+ response = await saas.async_request_with_token(
208
+ method="GET",
209
+ url="/api/data/list"
210
+ )
211
+ print(response.json())
212
+
213
+ asyncio.run(main())
214
+ ```
215
+
216
+ ### 使用缓存
217
+
218
+ ```python
219
+ import diskcache
220
+ from py_wisharetec_toolkit.saas import Saas
221
+
222
+ cache = diskcache.Cache("./cache")
223
+
224
+ saas = Saas(
225
+ account="test",
226
+ password="password",
227
+ cache_config={
228
+ "instance": cache,
229
+ "key": "saas_token",
230
+ "expire": 7100
231
+ }
232
+ )
233
+
234
+ # 自动从缓存获取或刷新 Token
235
+ saas.refresh_token()
236
+ ```
237
+
238
+ ## 作者
239
+
240
+ **Guolei**
241
+
242
+ - 邮箱: 174000902@qq.com
243
+
244
+ ## 项目主页
245
+
246
+ - **Gitee**: [https://gitee.com/guolei19850528/py_wisharetec_toolkit](https://gitee.com/guolei19850528/py_wisharetec_toolkit)
247
+
248
+ ## 许可证
249
+
250
+ MIT License
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/py_wisharetec_toolkit/__init__.py
5
+ src/py_wisharetec_toolkit.egg-info/PKG-INFO
6
+ src/py_wisharetec_toolkit.egg-info/SOURCES.txt
7
+ src/py_wisharetec_toolkit.egg-info/dependency_links.txt
8
+ src/py_wisharetec_toolkit.egg-info/requires.txt
9
+ src/py_wisharetec_toolkit.egg-info/top_level.txt
10
+ src/py_wisharetec_toolkit/saas/__init__.py
11
+ src/py_wisharetec_toolkit/saas/utils.py
@@ -0,0 +1,13 @@
1
+ httpx>=0.27.0
2
+ pydantic>=2.0
3
+ jsonpath-ng>=1.5.3
4
+ jsonschema>=4.21.0
5
+ diskcache>=5.6.3
6
+ redis>=4.6.0
7
+ py-httpx-toolkit>=1.0.0
8
+
9
+ [dev]
10
+ pytest>=7.0
11
+ pytest-cov>=4.0
12
+ setuptools>=61.0
13
+ twine>=4.0