py-tiehu 0.1.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.
- py_tiehu-0.1.0/LICENSE +21 -0
- py_tiehu-0.1.0/PKG-INFO +277 -0
- py_tiehu-0.1.0/README.md +224 -0
- py_tiehu-0.1.0/pyproject.toml +45 -0
- py_tiehu-0.1.0/setup.cfg +4 -0
- py_tiehu-0.1.0/src/py_tiehu/__init__.py +234 -0
- py_tiehu-0.1.0/src/py_tiehu/responses.py +29 -0
- py_tiehu-0.1.0/src/py_tiehu/utils.py +103 -0
- py_tiehu-0.1.0/src/py_tiehu.egg-info/PKG-INFO +277 -0
- py_tiehu-0.1.0/src/py_tiehu.egg-info/SOURCES.txt +11 -0
- py_tiehu-0.1.0/src/py_tiehu.egg-info/dependency_links.txt +1 -0
- py_tiehu-0.1.0/src/py_tiehu.egg-info/requires.txt +10 -0
- py_tiehu-0.1.0/src/py_tiehu.egg-info/top_level.txt +1 -0
py_tiehu-0.1.0/LICENSE
ADDED
|
@@ -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.
|
py_tiehu-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: py-tiehu
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: PyTiehu 是铁虎停车场管理系统的 Python SDK,提供同步和异步两种调用方式,实现完整的请求签名机制,用于与铁虎停车场管理系统进行 API 交互。
|
|
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_tiehu
|
|
29
|
+
Project-URL: Repository, https://gitee.com/guolei19850528/py_tiehu.git
|
|
30
|
+
Keywords: tiehu,python,client,api,铁虎,停车场
|
|
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
|
+
Provides-Extra: dev
|
|
48
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
50
|
+
Requires-Dist: setuptools>=61.0; extra == "dev"
|
|
51
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
52
|
+
Dynamic: license-file
|
|
53
|
+
|
|
54
|
+
# PyTiehu - 铁虎停车场 API Python SDK
|
|
55
|
+
|
|
56
|
+
[](https://python.org)
|
|
57
|
+
[](LICENSE)
|
|
58
|
+
|
|
59
|
+
PyTiehu 是铁虎停车场管理系统的 Python SDK,提供同步和异步两种调用方式,实现完整的请求签名机制,用于与铁虎停车场管理系统进行
|
|
60
|
+
API 交互。
|
|
61
|
+
|
|
62
|
+
## 功能特性
|
|
63
|
+
|
|
64
|
+
- ✅ 自动生成请求签名(MD5 算法)
|
|
65
|
+
- ✅ 支持同步/异步 HTTP 请求
|
|
66
|
+
- ✅ 自动添加公共请求参数(parkingId、timestamp、sign)
|
|
67
|
+
- ✅ 灵活的客户端配置选项
|
|
68
|
+
- ✅ Pydantic 响应模型支持
|
|
69
|
+
|
|
70
|
+
## 安装
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install py_tiehu
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 快速开始
|
|
77
|
+
|
|
78
|
+
### 同步客户端
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from py_tiehu import Pklot
|
|
82
|
+
|
|
83
|
+
# 初始化客户端
|
|
84
|
+
client = Pklot(
|
|
85
|
+
base_url="https://isc.example.com",
|
|
86
|
+
parking_id="park001",
|
|
87
|
+
app_key="your_app_secret"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# 发送请求
|
|
91
|
+
response = client.request(
|
|
92
|
+
url="/api/v1/parking/query",
|
|
93
|
+
json={"plateNo": "京A12345"}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# 处理响应
|
|
97
|
+
print(response.json())
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 异步客户端
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import asyncio
|
|
104
|
+
from py_tiehu import Pklot
|
|
105
|
+
|
|
106
|
+
# 初始化客户端
|
|
107
|
+
client = Pklot(
|
|
108
|
+
base_url="https://isc.example.com",
|
|
109
|
+
parking_id="park001",
|
|
110
|
+
app_key="your_app_secret"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# 异步发送请求
|
|
115
|
+
async def main():
|
|
116
|
+
response = await client.async_request(
|
|
117
|
+
url="/api/v1/parking/query",
|
|
118
|
+
json={"plateNo": "京A12345"}
|
|
119
|
+
)
|
|
120
|
+
print(response.json())
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
asyncio.run(main())
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## API 文档
|
|
127
|
+
|
|
128
|
+
### Pklot 类
|
|
129
|
+
|
|
130
|
+
#### 初始化参数
|
|
131
|
+
|
|
132
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
133
|
+
|-----------------|------|----|--------------------------|
|
|
134
|
+
| `base_url` | str | 是 | 停车场管理系统服务器基础 URL |
|
|
135
|
+
| `parking_id` | str | 是 | 停车场 ID |
|
|
136
|
+
| `app_key` | str | 是 | 应用密钥,用于生成请求签名 |
|
|
137
|
+
| `client_kwargs` | dict | 否 | 传递给 httpx.Client 的额外配置参数 |
|
|
138
|
+
|
|
139
|
+
#### 方法
|
|
140
|
+
|
|
141
|
+
| 方法 | 说明 | 返回值 |
|
|
142
|
+
|---------------------------|---------------|---------------------|
|
|
143
|
+
| `client()` | 创建同步 HTTP 客户端 | `httpx.Client` |
|
|
144
|
+
| `async_client()` | 创建异步 HTTP 客户端 | `httpx.AsyncClient` |
|
|
145
|
+
| `signature(data)` | 生成请求签名 | `str` |
|
|
146
|
+
| `request(**kwargs)` | 发送同步请求 | `httpx.Response` |
|
|
147
|
+
| `async_request(**kwargs)` | 发送异步请求 | `httpx.Response` |
|
|
148
|
+
|
|
149
|
+
### 签名算法
|
|
150
|
+
|
|
151
|
+
签名生成步骤:
|
|
152
|
+
|
|
153
|
+
1. 排除数据中的 `appKey` 字段
|
|
154
|
+
2. 对剩余字段按键名进行升序排序
|
|
155
|
+
3. 将排序后的字段以 `key=value` 格式用 `&` 连接
|
|
156
|
+
4. 尾部拼接 `appKey` 的 MD5 值(大写)
|
|
157
|
+
5. 对拼接后的完整字符串进行 MD5 计算并转为大写
|
|
158
|
+
|
|
159
|
+
### 工具函数
|
|
160
|
+
|
|
161
|
+
#### `timestamp()`
|
|
162
|
+
|
|
163
|
+
生成当前时间戳(毫秒)
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from py_tiehu.utils import timestamp
|
|
167
|
+
|
|
168
|
+
ts = timestamp() # 输出示例: 1630000000000
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### `json_find_first(expression, data)`
|
|
172
|
+
|
|
173
|
+
使用 JSONPath 表达式从数据中查找第一个匹配项
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from py_tiehu.utils import json_find_first
|
|
177
|
+
|
|
178
|
+
result = json_find_first("$.data[0].name", response.json())
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### `convert_to_status_eq_1(response)`
|
|
182
|
+
|
|
183
|
+
将 HTTP 响应或字典转换为 STATUS_EQ_1 模型对象
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from py_tiehu.utils import convert_to_status_eq_1
|
|
187
|
+
|
|
188
|
+
result = convert_to_status_eq_1(response)
|
|
189
|
+
print(result.status) # 1
|
|
190
|
+
print(result.Data) # 响应数据
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 响应模型
|
|
194
|
+
|
|
195
|
+
### Base
|
|
196
|
+
|
|
197
|
+
所有 API 响应的基类:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
class Base(BaseModel):
|
|
201
|
+
status: Union[int, str] # 错误码,1表示成功,非1表示失败
|
|
202
|
+
message: Optional[str] # 错误信息描述
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### STATUS_EQ_1
|
|
206
|
+
|
|
207
|
+
成功响应模型:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
class STATUS_EQ_1(Base):
|
|
211
|
+
status: Literal[1, "1"] # 成功,值为1
|
|
212
|
+
Data: Any # 成功响应数据
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 配置说明
|
|
216
|
+
|
|
217
|
+
### 默认配置
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
{
|
|
221
|
+
"base_url": "<your_base_url>",
|
|
222
|
+
"verify": False, # 禁用 SSL 证书验证
|
|
223
|
+
"timeout": 120 # 超时时间 120 秒
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 自定义配置
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
client = Pklot(
|
|
231
|
+
base_url="https://isc.example.com",
|
|
232
|
+
parking_id="park001",
|
|
233
|
+
app_key="your_app_secret",
|
|
234
|
+
client_kwargs={
|
|
235
|
+
"timeout": 60,
|
|
236
|
+
"verify": True,
|
|
237
|
+
"headers": {"X-Custom": "value"}
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## 示例
|
|
243
|
+
|
|
244
|
+
### 查询车辆信息
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
response = client.request(
|
|
248
|
+
url="/api/v1/vehicle/query",
|
|
249
|
+
json={
|
|
250
|
+
"plateNo": "京A12345",
|
|
251
|
+
"parkingId": "park001"
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 批量查询
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
response = client.request(
|
|
260
|
+
url="/api/v1/vehicle/batch",
|
|
261
|
+
json={
|
|
262
|
+
"plateNos": ["京A12345", "京B67890"],
|
|
263
|
+
"pageIndex": 1,
|
|
264
|
+
"pageSize": 20
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## 主页
|
|
270
|
+
|
|
271
|
+
[https://gitee.com/guolei19850528/py_tiehu](https://gitee.com/guolei19850528/py_tiehu)
|
|
272
|
+
|
|
273
|
+
## 许可证
|
|
274
|
+
|
|
275
|
+
MIT License
|
|
276
|
+
|
|
277
|
+
## 开发
|
py_tiehu-0.1.0/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# PyTiehu - 铁虎停车场 API Python SDK
|
|
2
|
+
|
|
3
|
+
[](https://python.org)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
PyTiehu 是铁虎停车场管理系统的 Python SDK,提供同步和异步两种调用方式,实现完整的请求签名机制,用于与铁虎停车场管理系统进行
|
|
7
|
+
API 交互。
|
|
8
|
+
|
|
9
|
+
## 功能特性
|
|
10
|
+
|
|
11
|
+
- ✅ 自动生成请求签名(MD5 算法)
|
|
12
|
+
- ✅ 支持同步/异步 HTTP 请求
|
|
13
|
+
- ✅ 自动添加公共请求参数(parkingId、timestamp、sign)
|
|
14
|
+
- ✅ 灵活的客户端配置选项
|
|
15
|
+
- ✅ Pydantic 响应模型支持
|
|
16
|
+
|
|
17
|
+
## 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install py_tiehu
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 快速开始
|
|
24
|
+
|
|
25
|
+
### 同步客户端
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from py_tiehu import Pklot
|
|
29
|
+
|
|
30
|
+
# 初始化客户端
|
|
31
|
+
client = Pklot(
|
|
32
|
+
base_url="https://isc.example.com",
|
|
33
|
+
parking_id="park001",
|
|
34
|
+
app_key="your_app_secret"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# 发送请求
|
|
38
|
+
response = client.request(
|
|
39
|
+
url="/api/v1/parking/query",
|
|
40
|
+
json={"plateNo": "京A12345"}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# 处理响应
|
|
44
|
+
print(response.json())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 异步客户端
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import asyncio
|
|
51
|
+
from py_tiehu import Pklot
|
|
52
|
+
|
|
53
|
+
# 初始化客户端
|
|
54
|
+
client = Pklot(
|
|
55
|
+
base_url="https://isc.example.com",
|
|
56
|
+
parking_id="park001",
|
|
57
|
+
app_key="your_app_secret"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# 异步发送请求
|
|
62
|
+
async def main():
|
|
63
|
+
response = await client.async_request(
|
|
64
|
+
url="/api/v1/parking/query",
|
|
65
|
+
json={"plateNo": "京A12345"}
|
|
66
|
+
)
|
|
67
|
+
print(response.json())
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
asyncio.run(main())
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API 文档
|
|
74
|
+
|
|
75
|
+
### Pklot 类
|
|
76
|
+
|
|
77
|
+
#### 初始化参数
|
|
78
|
+
|
|
79
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
80
|
+
|-----------------|------|----|--------------------------|
|
|
81
|
+
| `base_url` | str | 是 | 停车场管理系统服务器基础 URL |
|
|
82
|
+
| `parking_id` | str | 是 | 停车场 ID |
|
|
83
|
+
| `app_key` | str | 是 | 应用密钥,用于生成请求签名 |
|
|
84
|
+
| `client_kwargs` | dict | 否 | 传递给 httpx.Client 的额外配置参数 |
|
|
85
|
+
|
|
86
|
+
#### 方法
|
|
87
|
+
|
|
88
|
+
| 方法 | 说明 | 返回值 |
|
|
89
|
+
|---------------------------|---------------|---------------------|
|
|
90
|
+
| `client()` | 创建同步 HTTP 客户端 | `httpx.Client` |
|
|
91
|
+
| `async_client()` | 创建异步 HTTP 客户端 | `httpx.AsyncClient` |
|
|
92
|
+
| `signature(data)` | 生成请求签名 | `str` |
|
|
93
|
+
| `request(**kwargs)` | 发送同步请求 | `httpx.Response` |
|
|
94
|
+
| `async_request(**kwargs)` | 发送异步请求 | `httpx.Response` |
|
|
95
|
+
|
|
96
|
+
### 签名算法
|
|
97
|
+
|
|
98
|
+
签名生成步骤:
|
|
99
|
+
|
|
100
|
+
1. 排除数据中的 `appKey` 字段
|
|
101
|
+
2. 对剩余字段按键名进行升序排序
|
|
102
|
+
3. 将排序后的字段以 `key=value` 格式用 `&` 连接
|
|
103
|
+
4. 尾部拼接 `appKey` 的 MD5 值(大写)
|
|
104
|
+
5. 对拼接后的完整字符串进行 MD5 计算并转为大写
|
|
105
|
+
|
|
106
|
+
### 工具函数
|
|
107
|
+
|
|
108
|
+
#### `timestamp()`
|
|
109
|
+
|
|
110
|
+
生成当前时间戳(毫秒)
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from py_tiehu.utils import timestamp
|
|
114
|
+
|
|
115
|
+
ts = timestamp() # 输出示例: 1630000000000
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### `json_find_first(expression, data)`
|
|
119
|
+
|
|
120
|
+
使用 JSONPath 表达式从数据中查找第一个匹配项
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from py_tiehu.utils import json_find_first
|
|
124
|
+
|
|
125
|
+
result = json_find_first("$.data[0].name", response.json())
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `convert_to_status_eq_1(response)`
|
|
129
|
+
|
|
130
|
+
将 HTTP 响应或字典转换为 STATUS_EQ_1 模型对象
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from py_tiehu.utils import convert_to_status_eq_1
|
|
134
|
+
|
|
135
|
+
result = convert_to_status_eq_1(response)
|
|
136
|
+
print(result.status) # 1
|
|
137
|
+
print(result.Data) # 响应数据
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 响应模型
|
|
141
|
+
|
|
142
|
+
### Base
|
|
143
|
+
|
|
144
|
+
所有 API 响应的基类:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
class Base(BaseModel):
|
|
148
|
+
status: Union[int, str] # 错误码,1表示成功,非1表示失败
|
|
149
|
+
message: Optional[str] # 错误信息描述
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### STATUS_EQ_1
|
|
153
|
+
|
|
154
|
+
成功响应模型:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
class STATUS_EQ_1(Base):
|
|
158
|
+
status: Literal[1, "1"] # 成功,值为1
|
|
159
|
+
Data: Any # 成功响应数据
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 配置说明
|
|
163
|
+
|
|
164
|
+
### 默认配置
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
{
|
|
168
|
+
"base_url": "<your_base_url>",
|
|
169
|
+
"verify": False, # 禁用 SSL 证书验证
|
|
170
|
+
"timeout": 120 # 超时时间 120 秒
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 自定义配置
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
client = Pklot(
|
|
178
|
+
base_url="https://isc.example.com",
|
|
179
|
+
parking_id="park001",
|
|
180
|
+
app_key="your_app_secret",
|
|
181
|
+
client_kwargs={
|
|
182
|
+
"timeout": 60,
|
|
183
|
+
"verify": True,
|
|
184
|
+
"headers": {"X-Custom": "value"}
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 示例
|
|
190
|
+
|
|
191
|
+
### 查询车辆信息
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
response = client.request(
|
|
195
|
+
url="/api/v1/vehicle/query",
|
|
196
|
+
json={
|
|
197
|
+
"plateNo": "京A12345",
|
|
198
|
+
"parkingId": "park001"
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 批量查询
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
response = client.request(
|
|
207
|
+
url="/api/v1/vehicle/batch",
|
|
208
|
+
json={
|
|
209
|
+
"plateNos": ["京A12345", "京B67890"],
|
|
210
|
+
"pageIndex": 1,
|
|
211
|
+
"pageSize": 20
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## 主页
|
|
217
|
+
|
|
218
|
+
[https://gitee.com/guolei19850528/py_tiehu](https://gitee.com/guolei19850528/py_tiehu)
|
|
219
|
+
|
|
220
|
+
## 许可证
|
|
221
|
+
|
|
222
|
+
MIT License
|
|
223
|
+
|
|
224
|
+
## 开发
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
[project]
|
|
5
|
+
name = "py-tiehu"
|
|
6
|
+
version = "0.1.0"
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Guolei", email = "174000902@qq.com" }
|
|
10
|
+
]
|
|
11
|
+
description = "PyTiehu 是铁虎停车场管理系统的 Python SDK,提供同步和异步两种调用方式,实现完整的请求签名机制,用于与铁虎停车场管理系统进行 API 交互。"
|
|
12
|
+
keywords = ["tiehu", "python", "client", "api", "铁虎", "停车场"]
|
|
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
|
+
]
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=7.0",
|
|
35
|
+
"pytest-cov>=4.0",
|
|
36
|
+
"setuptools>=61.0",
|
|
37
|
+
"twine>=4.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
"Homepage" = "https://gitee.com/guolei19850528/py_tiehu"
|
|
42
|
+
"Repository" = "https://gitee.com/guolei19850528/py_tiehu.git"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
py_tiehu-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: UTF-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
铁虎 停车场 API Python SDK
|
|
5
|
+
|
|
6
|
+
提供同步和异步两种调用方式,实现完整的请求签名机制,
|
|
7
|
+
用于与铁虎停车场管理系统进行 API 交互。
|
|
8
|
+
|
|
9
|
+
主要功能:
|
|
10
|
+
- 自动生成请求签名(MD5算法)
|
|
11
|
+
- 支持同步/异步 HTTP 请求
|
|
12
|
+
- 自动添加公共请求参数(parkingId、timestamp、sign)
|
|
13
|
+
- 灵活的客户端配置选项
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import hashlib
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
import httpx
|
|
20
|
+
|
|
21
|
+
from .utils import timestamp
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Pklot:
|
|
25
|
+
"""
|
|
26
|
+
铁虎停车场 API 客户端类
|
|
27
|
+
|
|
28
|
+
提供与铁虎 停车场管理系统交互的核心功能,
|
|
29
|
+
支持同步和异步两种请求模式,自动处理请求签名和公共参数。
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
base_url (str): 停车场管理系统 服务器基础 URL
|
|
33
|
+
parking_id (str): 停车场 ID,用于标识目标停车场
|
|
34
|
+
app_key (str): 应用密钥,用于生成请求签名
|
|
35
|
+
client_kwargs (dict): HTTP 客户端配置参数
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
# 同步客户端
|
|
39
|
+
sync_client = Pklot(
|
|
40
|
+
base_url="https://isc.example.com",
|
|
41
|
+
parking_id="park001",
|
|
42
|
+
app_key="your_app_secret"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# 异步客户端
|
|
46
|
+
async_client = Pklot(
|
|
47
|
+
base_url="https://isc.example.com",
|
|
48
|
+
parking_id="park001",
|
|
49
|
+
app_key="your_app_secret",
|
|
50
|
+
use_async_client=True
|
|
51
|
+
)
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
base_url: Optional[str] = None,
|
|
57
|
+
parking_id: Optional[str] = None,
|
|
58
|
+
app_key: Optional[str] = None,
|
|
59
|
+
client_kwargs: Optional[dict] = None
|
|
60
|
+
):
|
|
61
|
+
"""
|
|
62
|
+
初始化 Pklot 客户端
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
base_url: 停车场管理系统 服务器基础 URL,如 "https://isc.example.com"
|
|
66
|
+
parking_id: 停车场 ID,由停车场 系统分配
|
|
67
|
+
app_key: 应用密钥,用于请求签名生成
|
|
68
|
+
client_kwargs: 传递给 httpx.Client 的额外配置参数
|
|
69
|
+
|
|
70
|
+
Note:
|
|
71
|
+
- base_url 末尾的斜杠会被自动移除
|
|
72
|
+
- client_kwargs 支持 httpx 客户端的所有配置选项
|
|
73
|
+
- 默认超时时间为 120 秒
|
|
74
|
+
- 默认禁用 SSL 证书验证(verify=False)
|
|
75
|
+
"""
|
|
76
|
+
# 处理基础 URL,移除末尾斜杠
|
|
77
|
+
self.base_url = base_url or ""
|
|
78
|
+
self.base_url = self.base_url[:-1] if self.base_url.endswith("/") else self.base_url
|
|
79
|
+
|
|
80
|
+
# 存储核心配置参数
|
|
81
|
+
self.parking_id = parking_id or ""
|
|
82
|
+
self.app_key = app_key or ""
|
|
83
|
+
self.client_kwargs = client_kwargs or {}
|
|
84
|
+
|
|
85
|
+
self.client_kwargs = {
|
|
86
|
+
**{
|
|
87
|
+
"base_url": self.base_url,
|
|
88
|
+
"verify": False,
|
|
89
|
+
"timeout": 120,
|
|
90
|
+
},
|
|
91
|
+
**self.client_kwargs,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
def client(self) -> httpx.Client:
|
|
95
|
+
"""
|
|
96
|
+
创建并返回同步HTTP客户端
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
httpx.Client: 配置好的同步HTTP客户端实例
|
|
100
|
+
"""
|
|
101
|
+
return httpx.Client(**self.client_kwargs)
|
|
102
|
+
|
|
103
|
+
def async_client(self) -> httpx.AsyncClient:
|
|
104
|
+
"""
|
|
105
|
+
创建并返回异步HTTP客户端
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
httpx.AsyncClient: 配置好的异步HTTP客户端实例
|
|
109
|
+
"""
|
|
110
|
+
return httpx.AsyncClient(**self.client_kwargs)
|
|
111
|
+
|
|
112
|
+
def signature(self, data: Optional[dict] = None) -> str:
|
|
113
|
+
"""
|
|
114
|
+
生成请求签名,用于验证 API 请求的合法性和完整性
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
data: 需要签名的数据字典,包含 API 请求的参数
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
str: 生成的 MD5 签名字符串(大写),用于 API 请求的 sign 参数
|
|
121
|
+
|
|
122
|
+
签名算法说明:
|
|
123
|
+
1. 排除数据中的 appKey 字段
|
|
124
|
+
2. 对剩余字段按键名进行升序排序
|
|
125
|
+
3. 将排序后的字段以 "key=value" 格式用 "&" 连接
|
|
126
|
+
4. 尾部拼接 appKey 的 MD5 值(大写)
|
|
127
|
+
5. 对拼接后的完整字符串进行 MD5 计算并转为大写
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
>>> client = Parking(parking_id="123", app_key="secret")
|
|
131
|
+
>>> sign = client.signature({"parkingId": "123", "timestamp": 1234567890})
|
|
132
|
+
>>> print(sign) # 输出类似: A1B2C3D4E5F67890ABCDEF1234567890
|
|
133
|
+
"""
|
|
134
|
+
# 确保 data 是字典类型,避免后续操作出错
|
|
135
|
+
data = data or {}
|
|
136
|
+
temp_string = ""
|
|
137
|
+
|
|
138
|
+
# 如果有数据需要签名
|
|
139
|
+
if len(data.keys()):
|
|
140
|
+
# 对字典键进行排序,确保签名的一致性(升序排列)
|
|
141
|
+
data_sorted = sorted(data.keys())
|
|
142
|
+
if isinstance(data_sorted, list):
|
|
143
|
+
# 构建待签名字符串,排除 appKey 字段
|
|
144
|
+
temp_string = "&".join([
|
|
145
|
+
f"{i}={data[i]}"
|
|
146
|
+
for i in data_sorted if i != "appKey" # 排除 appKey 字段,避免重复签名
|
|
147
|
+
]) + f"{hashlib.md5(self.app_key.encode('utf-8')).hexdigest().upper()}"
|
|
148
|
+
|
|
149
|
+
# 生成最终的 MD5 签名并转换为大写格式
|
|
150
|
+
return hashlib.md5(temp_string.encode('utf-8')).hexdigest().upper()
|
|
151
|
+
|
|
152
|
+
def request(self, client: Optional[httpx.Client] = None, **kwargs):
|
|
153
|
+
"""
|
|
154
|
+
同步请求方法
|
|
155
|
+
|
|
156
|
+
自动添加公共请求参数(parkingId、timestamp、sign),
|
|
157
|
+
并生成请求签名,然后发送同步 HTTP 请求。
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
client: 可选的同步客户端实例,若不提供则使用内置客户端
|
|
161
|
+
**kwargs: 传递给 client.request 的额外参数,支持所有 httpx 参数
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
httpx.Response: HTTP 响应对象
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
>>> client = Parking(base_url="https://isc.example.com", ...)
|
|
168
|
+
>>> response = client.request(url="/api/v1/parking/query", json={"plateNo": "京A12345"})
|
|
169
|
+
>>> print(response.json())
|
|
170
|
+
"""
|
|
171
|
+
ts = timestamp()
|
|
172
|
+
kwargs = kwargs or {}
|
|
173
|
+
kwargs = {
|
|
174
|
+
**{
|
|
175
|
+
"method": "POST",
|
|
176
|
+
"json": {
|
|
177
|
+
"parkingId": self.parking_id, # 停车场 ID,必填公共参数
|
|
178
|
+
"timestamp": ts, # 时间戳,用于防止请求重放
|
|
179
|
+
"sign": self.signature({ # 生成请求签名
|
|
180
|
+
"parkingId": self.parking_id,
|
|
181
|
+
"timestamp": ts,
|
|
182
|
+
})
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
**kwargs
|
|
186
|
+
}
|
|
187
|
+
if isinstance(client, httpx.Client):
|
|
188
|
+
response = client.request(**kwargs)
|
|
189
|
+
else:
|
|
190
|
+
with self.client() as _client:
|
|
191
|
+
response = _client.request(**kwargs)
|
|
192
|
+
return response
|
|
193
|
+
|
|
194
|
+
async def async_request(self, client: Optional[httpx.AsyncClient] = None, **kwargs) -> httpx.Response:
|
|
195
|
+
"""
|
|
196
|
+
异步请求方法
|
|
197
|
+
|
|
198
|
+
自动添加公共请求参数(parkingId、timestamp、sign),
|
|
199
|
+
并生成请求签名,然后发送异步 HTTP 请求。
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
client: 可选的异步客户端实例,若不提供则使用内置客户端
|
|
203
|
+
**kwargs: 传递给 client.request 的额外参数,支持所有 httpx 参数
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
httpx.Response: HTTP 响应对象
|
|
207
|
+
|
|
208
|
+
Example:
|
|
209
|
+
>>> client = Parking(base_url="https://isc.example.com", use_async_client=True, ...)
|
|
210
|
+
>>> response = await client.async_request(url="/api/v1/parking/query", json={"plateNo": "京A12345"})
|
|
211
|
+
>>> print(response.json())
|
|
212
|
+
"""
|
|
213
|
+
ts = timestamp()
|
|
214
|
+
kwargs = kwargs or {}
|
|
215
|
+
kwargs = {
|
|
216
|
+
**{
|
|
217
|
+
"method": "POST",
|
|
218
|
+
"json": {
|
|
219
|
+
"parkingId": self.parking_id, # 停车场 ID,必填公共参数
|
|
220
|
+
"timestamp": ts, # 时间戳,用于防止请求重放
|
|
221
|
+
"sign": self.signature({ # 生成请求签名
|
|
222
|
+
"parkingId": self.parking_id,
|
|
223
|
+
"timestamp": ts,
|
|
224
|
+
})
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
**kwargs
|
|
228
|
+
}
|
|
229
|
+
if isinstance(client, httpx.AsyncClient):
|
|
230
|
+
response = await client.request(**kwargs)
|
|
231
|
+
else:
|
|
232
|
+
async with self.async_client() as _client:
|
|
233
|
+
response = await _client.request(**kwargs)
|
|
234
|
+
return response
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: UTF-8 -*-
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
from typing import Literal, Union, Any, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Base(BaseModel):
|
|
9
|
+
"""
|
|
10
|
+
iSecure Center响应基类
|
|
11
|
+
|
|
12
|
+
所有API响应都包含错误码和错误信息字段
|
|
13
|
+
"""
|
|
14
|
+
status: Union[int, str] = Field(..., title="错误码", description="错误码,1表示成功,非1表示失败")
|
|
15
|
+
message: Optional[str] = Field(default=None, title="错误信息", description="错误信息描述")
|
|
16
|
+
|
|
17
|
+
model_config = {
|
|
18
|
+
"extra": "allow" # 允许额外动态字段
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class STATUS_EQ_1(Base):
|
|
23
|
+
"""
|
|
24
|
+
成功响应模型
|
|
25
|
+
|
|
26
|
+
继承自Base,用于成功接口的响应
|
|
27
|
+
"""
|
|
28
|
+
status: Literal[1, "1"] = Field(..., title="错误码", description="成功,值为1")
|
|
29
|
+
Data: Any = Field(title="数据", description="成功响应数据")
|
|
@@ -0,0 +1,103 @@
|
|
|
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
|
+
from .responses import STATUS_EQ_1
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def json_find_first(expression: str, data: Any) -> Any:
|
|
14
|
+
"""
|
|
15
|
+
使用 JSONPath 表达式从数据中查找第一个匹配项
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
expression: JSONPath 表达式,用于指定要查找的数据路径
|
|
19
|
+
data: 待查询的 JSON 数据
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Any: 第一个匹配的值,如果没有匹配项则返回 None
|
|
23
|
+
"""
|
|
24
|
+
results = [i.value for i in parse(expression).find(data)]
|
|
25
|
+
if isinstance(results, list) and len(results) > 0:
|
|
26
|
+
return results[0]
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def json_is_valid(schema: Optional[dict], data: Any) -> bool:
|
|
31
|
+
"""
|
|
32
|
+
校验 JSON 数据是否符合指定的 JSON Schema
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
schema: JSON Schema 字典
|
|
36
|
+
data: 待校验的 JSON 数据
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
bool: 校验是否成功
|
|
40
|
+
"""
|
|
41
|
+
return Draft202012Validator(schema).is_valid(data)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def timestamp() -> int:
|
|
45
|
+
"""
|
|
46
|
+
生成当前时间戳(毫秒)
|
|
47
|
+
|
|
48
|
+
返回:
|
|
49
|
+
int: 当前时间戳(毫秒),用于请求的时效性验证
|
|
50
|
+
|
|
51
|
+
示例:
|
|
52
|
+
>>> ts = utils.timestamp()
|
|
53
|
+
>>> print(ts) # 输出示例: 1630000000000
|
|
54
|
+
"""
|
|
55
|
+
return int((datetime.now().timestamp() * 1000))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def convert_to_status_eq_1(response: Union[httpx.Response, dict]) -> STATUS_EQ_1:
|
|
59
|
+
"""
|
|
60
|
+
将 HTTP 响应或字典转换为 STATUS_EQ_1 模型对象
|
|
61
|
+
|
|
62
|
+
统一处理 httpx.Response 对象和字典,将其转换为标准化的 STATUS_EQ_1 响应模型。
|
|
63
|
+
|
|
64
|
+
参数:
|
|
65
|
+
response (Union[httpx.Response, dict]): HTTP 响应对象或字典数据
|
|
66
|
+
|
|
67
|
+
返回:
|
|
68
|
+
STATUS_EQ_1: 标准化的响应模型对象,包含 status、message 和 Data 字段
|
|
69
|
+
|
|
70
|
+
处理逻辑:
|
|
71
|
+
- 如果输入是 httpx.Response 对象,先调用 json() 方法解析响应体
|
|
72
|
+
- 如果输入是字典,直接传入 STATUS_EQ_1 构造函数
|
|
73
|
+
"""
|
|
74
|
+
if isinstance(response, httpx.Response):
|
|
75
|
+
return STATUS_EQ_1(**response.json())
|
|
76
|
+
return STATUS_EQ_1(**response)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def status_eq_1_validator(
|
|
80
|
+
response: Union[httpx.Response, dict] = None,
|
|
81
|
+
schema: dict = {
|
|
82
|
+
"type": "object",
|
|
83
|
+
"properties": {
|
|
84
|
+
"status": {
|
|
85
|
+
"oneOf": [
|
|
86
|
+
{"type": "integer", "const": 1},
|
|
87
|
+
{"type": "string", "const": "1"}
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
"required": ["status"]
|
|
92
|
+
}
|
|
93
|
+
):
|
|
94
|
+
"""
|
|
95
|
+
校验 HTTP 响应或字典是否符合指定的 JSON Schema
|
|
96
|
+
|
|
97
|
+
:param response: HTTP 响应对象或字典数据
|
|
98
|
+
:param schema: JSON Schema 字典
|
|
99
|
+
:return: 校验是否成功
|
|
100
|
+
"""
|
|
101
|
+
if isinstance(response, httpx.Response):
|
|
102
|
+
return json_is_valid(schema, response.json())
|
|
103
|
+
return json_is_valid(schema, response)
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: py-tiehu
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: PyTiehu 是铁虎停车场管理系统的 Python SDK,提供同步和异步两种调用方式,实现完整的请求签名机制,用于与铁虎停车场管理系统进行 API 交互。
|
|
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_tiehu
|
|
29
|
+
Project-URL: Repository, https://gitee.com/guolei19850528/py_tiehu.git
|
|
30
|
+
Keywords: tiehu,python,client,api,铁虎,停车场
|
|
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
|
+
Provides-Extra: dev
|
|
48
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
50
|
+
Requires-Dist: setuptools>=61.0; extra == "dev"
|
|
51
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
52
|
+
Dynamic: license-file
|
|
53
|
+
|
|
54
|
+
# PyTiehu - 铁虎停车场 API Python SDK
|
|
55
|
+
|
|
56
|
+
[](https://python.org)
|
|
57
|
+
[](LICENSE)
|
|
58
|
+
|
|
59
|
+
PyTiehu 是铁虎停车场管理系统的 Python SDK,提供同步和异步两种调用方式,实现完整的请求签名机制,用于与铁虎停车场管理系统进行
|
|
60
|
+
API 交互。
|
|
61
|
+
|
|
62
|
+
## 功能特性
|
|
63
|
+
|
|
64
|
+
- ✅ 自动生成请求签名(MD5 算法)
|
|
65
|
+
- ✅ 支持同步/异步 HTTP 请求
|
|
66
|
+
- ✅ 自动添加公共请求参数(parkingId、timestamp、sign)
|
|
67
|
+
- ✅ 灵活的客户端配置选项
|
|
68
|
+
- ✅ Pydantic 响应模型支持
|
|
69
|
+
|
|
70
|
+
## 安装
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install py_tiehu
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 快速开始
|
|
77
|
+
|
|
78
|
+
### 同步客户端
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from py_tiehu import Pklot
|
|
82
|
+
|
|
83
|
+
# 初始化客户端
|
|
84
|
+
client = Pklot(
|
|
85
|
+
base_url="https://isc.example.com",
|
|
86
|
+
parking_id="park001",
|
|
87
|
+
app_key="your_app_secret"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# 发送请求
|
|
91
|
+
response = client.request(
|
|
92
|
+
url="/api/v1/parking/query",
|
|
93
|
+
json={"plateNo": "京A12345"}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# 处理响应
|
|
97
|
+
print(response.json())
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 异步客户端
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import asyncio
|
|
104
|
+
from py_tiehu import Pklot
|
|
105
|
+
|
|
106
|
+
# 初始化客户端
|
|
107
|
+
client = Pklot(
|
|
108
|
+
base_url="https://isc.example.com",
|
|
109
|
+
parking_id="park001",
|
|
110
|
+
app_key="your_app_secret"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# 异步发送请求
|
|
115
|
+
async def main():
|
|
116
|
+
response = await client.async_request(
|
|
117
|
+
url="/api/v1/parking/query",
|
|
118
|
+
json={"plateNo": "京A12345"}
|
|
119
|
+
)
|
|
120
|
+
print(response.json())
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
asyncio.run(main())
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## API 文档
|
|
127
|
+
|
|
128
|
+
### Pklot 类
|
|
129
|
+
|
|
130
|
+
#### 初始化参数
|
|
131
|
+
|
|
132
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
133
|
+
|-----------------|------|----|--------------------------|
|
|
134
|
+
| `base_url` | str | 是 | 停车场管理系统服务器基础 URL |
|
|
135
|
+
| `parking_id` | str | 是 | 停车场 ID |
|
|
136
|
+
| `app_key` | str | 是 | 应用密钥,用于生成请求签名 |
|
|
137
|
+
| `client_kwargs` | dict | 否 | 传递给 httpx.Client 的额外配置参数 |
|
|
138
|
+
|
|
139
|
+
#### 方法
|
|
140
|
+
|
|
141
|
+
| 方法 | 说明 | 返回值 |
|
|
142
|
+
|---------------------------|---------------|---------------------|
|
|
143
|
+
| `client()` | 创建同步 HTTP 客户端 | `httpx.Client` |
|
|
144
|
+
| `async_client()` | 创建异步 HTTP 客户端 | `httpx.AsyncClient` |
|
|
145
|
+
| `signature(data)` | 生成请求签名 | `str` |
|
|
146
|
+
| `request(**kwargs)` | 发送同步请求 | `httpx.Response` |
|
|
147
|
+
| `async_request(**kwargs)` | 发送异步请求 | `httpx.Response` |
|
|
148
|
+
|
|
149
|
+
### 签名算法
|
|
150
|
+
|
|
151
|
+
签名生成步骤:
|
|
152
|
+
|
|
153
|
+
1. 排除数据中的 `appKey` 字段
|
|
154
|
+
2. 对剩余字段按键名进行升序排序
|
|
155
|
+
3. 将排序后的字段以 `key=value` 格式用 `&` 连接
|
|
156
|
+
4. 尾部拼接 `appKey` 的 MD5 值(大写)
|
|
157
|
+
5. 对拼接后的完整字符串进行 MD5 计算并转为大写
|
|
158
|
+
|
|
159
|
+
### 工具函数
|
|
160
|
+
|
|
161
|
+
#### `timestamp()`
|
|
162
|
+
|
|
163
|
+
生成当前时间戳(毫秒)
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from py_tiehu.utils import timestamp
|
|
167
|
+
|
|
168
|
+
ts = timestamp() # 输出示例: 1630000000000
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### `json_find_first(expression, data)`
|
|
172
|
+
|
|
173
|
+
使用 JSONPath 表达式从数据中查找第一个匹配项
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from py_tiehu.utils import json_find_first
|
|
177
|
+
|
|
178
|
+
result = json_find_first("$.data[0].name", response.json())
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### `convert_to_status_eq_1(response)`
|
|
182
|
+
|
|
183
|
+
将 HTTP 响应或字典转换为 STATUS_EQ_1 模型对象
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from py_tiehu.utils import convert_to_status_eq_1
|
|
187
|
+
|
|
188
|
+
result = convert_to_status_eq_1(response)
|
|
189
|
+
print(result.status) # 1
|
|
190
|
+
print(result.Data) # 响应数据
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 响应模型
|
|
194
|
+
|
|
195
|
+
### Base
|
|
196
|
+
|
|
197
|
+
所有 API 响应的基类:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
class Base(BaseModel):
|
|
201
|
+
status: Union[int, str] # 错误码,1表示成功,非1表示失败
|
|
202
|
+
message: Optional[str] # 错误信息描述
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### STATUS_EQ_1
|
|
206
|
+
|
|
207
|
+
成功响应模型:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
class STATUS_EQ_1(Base):
|
|
211
|
+
status: Literal[1, "1"] # 成功,值为1
|
|
212
|
+
Data: Any # 成功响应数据
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 配置说明
|
|
216
|
+
|
|
217
|
+
### 默认配置
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
{
|
|
221
|
+
"base_url": "<your_base_url>",
|
|
222
|
+
"verify": False, # 禁用 SSL 证书验证
|
|
223
|
+
"timeout": 120 # 超时时间 120 秒
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 自定义配置
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
client = Pklot(
|
|
231
|
+
base_url="https://isc.example.com",
|
|
232
|
+
parking_id="park001",
|
|
233
|
+
app_key="your_app_secret",
|
|
234
|
+
client_kwargs={
|
|
235
|
+
"timeout": 60,
|
|
236
|
+
"verify": True,
|
|
237
|
+
"headers": {"X-Custom": "value"}
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## 示例
|
|
243
|
+
|
|
244
|
+
### 查询车辆信息
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
response = client.request(
|
|
248
|
+
url="/api/v1/vehicle/query",
|
|
249
|
+
json={
|
|
250
|
+
"plateNo": "京A12345",
|
|
251
|
+
"parkingId": "park001"
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 批量查询
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
response = client.request(
|
|
260
|
+
url="/api/v1/vehicle/batch",
|
|
261
|
+
json={
|
|
262
|
+
"plateNos": ["京A12345", "京B67890"],
|
|
263
|
+
"pageIndex": 1,
|
|
264
|
+
"pageSize": 20
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## 主页
|
|
270
|
+
|
|
271
|
+
[https://gitee.com/guolei19850528/py_tiehu](https://gitee.com/guolei19850528/py_tiehu)
|
|
272
|
+
|
|
273
|
+
## 许可证
|
|
274
|
+
|
|
275
|
+
MIT License
|
|
276
|
+
|
|
277
|
+
## 开发
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/py_tiehu/__init__.py
|
|
5
|
+
src/py_tiehu/responses.py
|
|
6
|
+
src/py_tiehu/utils.py
|
|
7
|
+
src/py_tiehu.egg-info/PKG-INFO
|
|
8
|
+
src/py_tiehu.egg-info/SOURCES.txt
|
|
9
|
+
src/py_tiehu.egg-info/dependency_links.txt
|
|
10
|
+
src/py_tiehu.egg-info/requires.txt
|
|
11
|
+
src/py_tiehu.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
py_tiehu
|