pixelarraythirdparty 1.1.0__py3-none-any.whl → 1.1.2__py3-none-any.whl

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.
@@ -15,44 +15,33 @@ class ProductManagerAsync(AsyncClient):
15
15
  sort_order: int,
16
16
  ):
17
17
  """
18
- 创建产品(异步版本)
19
-
20
- 功能说明:
18
+ description:
21
19
  创建新的产品,支持订阅产品和一次性产品,产品信息包括名称、描述、价格、分类等。
22
-
23
- 输入参数:
24
- name (str): 产品名称,必填
25
- description (str): 产品描述,必填
26
- price (float): 产品价格(元),必填
27
- category (str): 产品分类,必填
28
- status (str): 产品状态,必填,可选值:
29
- - "ACTIVE": 激活
30
- - "INACTIVE": 停用
31
- is_subscription (bool): 是否为订阅产品,必填
32
- subscription_period (str): 订阅周期,必填,可选值:
33
- - "MONTHLY": 月付
34
- - "YEARLY": 年付
35
- features (str): 产品特性,JSON格式字符串,必填
36
- sort_order (int): 排序权重,必填
37
-
38
- 返回字段:
39
- data (dict): 产品信息
40
- - id (int): 产品ID
41
- - name (str): 产品名称
42
- - description (str): 产品描述
43
- - price (float): 产品价格(元)
44
- - category (str): 产品分类
45
- - status (str): 产品状态
46
- - is_subscription (bool): 是否为订阅产品
47
- - subscription_period (str): 订阅周期
48
- - features (str): 产品特性(JSON格式)
49
- - sort_order (int): 排序权重
50
- - created_at (str): 产品创建时间
51
- - updated_at (str): 产品更新时间
52
- success (bool): 操作是否成功
53
-
54
- 异常情况:
55
- - 产品创建失败:返回错误信息"产品创建失败"
20
+ parameters:
21
+ name(str): 产品名称
22
+ description(str): 产品描述
23
+ price(float): 产品价格(元)
24
+ category(str): 产品分类
25
+ status(str): 产品状态,可选值:"ACTIVE"(激活)、"INACTIVE"(停用)
26
+ is_subscription(bool): 是否为订阅产品
27
+ subscription_period(str): 订阅周期,可选值:"MONTHLY"(月付)、"YEARLY"(年付)
28
+ features(str): 产品特性,JSON格式字符串
29
+ sort_order(int): 排序权重
30
+ return:
31
+ data(dict): 产品信息
32
+ - id(int): 产品ID
33
+ - name(str): 产品名称
34
+ - description(str): 产品描述
35
+ - price(float): 产品价格(元)
36
+ - category(str): 产品分类
37
+ - status(str): 产品状态
38
+ - is_subscription(bool): 是否为订阅产品
39
+ - subscription_period(str): 订阅周期
40
+ - features(str): 产品特性(JSON格式)
41
+ - sort_order(int): 排序权重
42
+ - created_at(str): 产品创建时间
43
+ - updated_at(str): 产品更新时间
44
+ success(bool): 操作是否成功
56
45
  """
57
46
  data = {
58
47
  "name": name,
@@ -79,42 +68,21 @@ class ProductManagerAsync(AsyncClient):
79
68
  name: str = None,
80
69
  ):
81
70
  """
82
- 获取产品列表(异步版本)
83
-
84
- 功能说明:
71
+ description:
85
72
  分页查询产品列表,支持按状态、分类和名称进行筛选。
86
-
87
- 输入参数:
88
- page (int, 可选): 页码,默认为1,最小值为1
89
- page_size (int, 可选): 每页数量,默认为10,范围为1-1000
90
- status (str, 可选): 产品状态筛选,可选值:
91
- - "ACTIVE": 激活
92
- - "INACTIVE": 停用
93
- category (str, 可选): 产品分类筛选
94
- name (str, 可选): 产品名称搜索,支持模糊匹配
95
-
96
- 返回字段:
97
- data (dict): 产品列表信息
98
- - products (list): 产品列表
99
- - id (int): 产品ID
100
- - name (str): 产品名称
101
- - description (str): 产品描述
102
- - price (float): 产品价格(元)
103
- - category (str): 产品分类
104
- - status (str): 产品状态
105
- - is_subscription (bool): 是否为订阅产品
106
- - subscription_period (str): 订阅周期
107
- - features (str): 产品特性(JSON格式)
108
- - sort_order (int): 排序权重
109
- - created_at (str): 产品创建时间
110
- - updated_at (str): 产品更新时间
111
- - total (int): 总产品数量
112
- - page (int): 当前页码
113
- - page_size (int): 每页数量
114
- success (bool): 操作是否成功
115
-
116
- 异常情况:
117
- - 获取产品列表失败:返回错误信息"获取产品列表失败"
73
+ parameters:
74
+ page(int): 页码
75
+ page_size(int): 每页数量
76
+ status(str): 产品状态筛选,可选值:"ACTIVE"(激活)、"INACTIVE"(停用)
77
+ category(str): 产品分类筛选
78
+ name(str): 产品名称搜索,支持模糊匹配
79
+ return:
80
+ data(dict): 产品列表信息
81
+ - products(list): 产品列表
82
+ - total(int): 总产品数量
83
+ - page(int): 当前页码
84
+ - page_size(int): 每页数量
85
+ success(bool): 操作是否成功
118
86
  """
119
87
  params = {
120
88
  "page": page,
@@ -133,33 +101,13 @@ class ProductManagerAsync(AsyncClient):
133
101
 
134
102
  async def get_product_detail(self, product_id: str):
135
103
  """
136
- 获取产品详情(异步版本)
137
-
138
- 功能说明:
104
+ description:
139
105
  根据产品ID获取产品的详细信息。
140
-
141
- 输入参数:
142
- product_id (str): 产品ID,必填
143
-
144
- 返回字段:
145
- data (dict): 产品详细信息
146
- - id (int): 产品ID
147
- - name (str): 产品名称
148
- - description (str): 产品描述
149
- - price (float): 产品价格(元)
150
- - category (str): 产品分类
151
- - status (str): 产品状态
152
- - is_subscription (bool): 是否为订阅产品
153
- - subscription_period (str): 订阅周期
154
- - features (str): 产品特性(JSON格式)
155
- - sort_order (int): 排序权重
156
- - created_at (str): 产品创建时间
157
- - updated_at (str): 产品更新时间
158
- success (bool): 操作是否成功
159
-
160
- 异常情况:
161
- - 产品不存在:返回错误信息"产品不存在"
162
- - 获取产品详情失败:返回错误信息"获取产品详情失败"
106
+ parameters:
107
+ product_id(str): 产品ID
108
+ return:
109
+ data(dict): 产品详细信息
110
+ success(bool): 操作是否成功
163
111
  """
164
112
  data, success = await self._request("GET", f"/api/products/{product_id}")
165
113
  if not success:
@@ -180,46 +128,34 @@ class ProductManagerAsync(AsyncClient):
180
128
  sort_order: int,
181
129
  ):
182
130
  """
183
- 更新产品信息(异步版本)
184
-
185
- 功能说明:
131
+ description:
186
132
  更新指定产品的信息,包括名称、描述、价格、状态等。
187
-
188
- 输入参数:
189
- product_id (str): 产品ID,必填
190
- name (str): 产品名称,必填
191
- description (str): 产品描述,必填
192
- price (float): 产品价格(元),必填
193
- category (str): 产品分类,必填
194
- status (str): 产品状态,必填,可选值:
195
- - "ACTIVE": 激活
196
- - "INACTIVE": 停用
197
- is_subscription (bool): 是否为订阅产品,必填
198
- subscription_period (str): 订阅周期,必填,可选值:
199
- - "MONTHLY": 月付
200
- - "YEARLY": 年付
201
- features (str): 产品特性,JSON格式字符串,必填
202
- sort_order (int): 排序权重,必填
203
-
204
- 返回字段:
205
- data (dict): 更新后的产品信息
206
- - id (int): 产品ID
207
- - name (str): 产品名称
208
- - description (str): 产品描述
209
- - price (float): 产品价格(元)
210
- - category (str): 产品分类
211
- - status (str): 产品状态
212
- - is_subscription (bool): 是否为订阅产品
213
- - subscription_period (str): 订阅周期
214
- - features (str): 产品特性(JSON格式)
215
- - sort_order (int): 排序权重
216
- - created_at (str): 产品创建时间
217
- - updated_at (str): 产品更新时间
218
- success (bool): 操作是否成功
219
-
220
- 异常情况:
221
- - 产品不存在:返回错误信息"产品不存在"
222
- - 产品更新失败:返回错误信息"产品更新失败"
133
+ parameters:
134
+ product_id(str): 产品ID
135
+ name(str): 产品名称
136
+ description(str): 产品描述
137
+ price(float): 产品价格(元)
138
+ category(str): 产品分类
139
+ status(str): 产品状态,可选值:"ACTIVE"(激活)、"INACTIVE"(停用)
140
+ is_subscription(bool): 是否为订阅产品
141
+ subscription_period(str): 订阅周期,可选值:"MONTHLY"(月付)、"YEARLY"(年付)
142
+ features(str): 产品特性,JSON格式字符串
143
+ sort_order(int): 排序权重
144
+ return:
145
+ data(dict): 更新后的产品信息
146
+ - id(int): 产品ID
147
+ - name(str): 产品名称
148
+ - description(str): 产品描述
149
+ - price(float): 产品价格(元)
150
+ - category(str): 产品分类
151
+ - status(str): 产品状态
152
+ - is_subscription(bool): 是否为订阅产品
153
+ - subscription_period(str): 订阅周期
154
+ - features(str): 产品特性(JSON格式)
155
+ - sort_order(int): 排序权重
156
+ - created_at(str): 产品创建时间
157
+ - updated_at(str): 产品更新时间
158
+ success(bool): 操作是否成功
223
159
  """
224
160
  data = {
225
161
  "name": name,
@@ -241,21 +177,13 @@ class ProductManagerAsync(AsyncClient):
241
177
 
242
178
  async def delete_product(self, product_id: str):
243
179
  """
244
- 删除产品(异步版本)
245
-
246
- 功能说明:
180
+ description:
247
181
  根据产品ID删除指定的产品记录。
248
-
249
- 输入参数:
250
- product_id (str): 产品ID,必填
251
-
252
- 返回字段:
253
- data (None): 删除成功时返回None
254
- success (bool): 操作是否成功
255
-
256
- 异常情况:
257
- - 产品不存在:返回错误信息"产品不存在"
258
- - 删除产品失败:返回错误信息"删除产品失败"
182
+ parameters:
183
+ product_id(str): 产品ID
184
+ return:
185
+ data(None): 删除成功时返回None
186
+ success(bool): 操作是否成功
259
187
  """
260
188
  data, success = await self._request("DELETE", f"/api/products/{product_id}")
261
189
  if not success:
@@ -264,21 +192,12 @@ class ProductManagerAsync(AsyncClient):
264
192
 
265
193
  async def get_product_categories(self):
266
194
  """
267
- 获取产品分类列表(异步版本)
268
-
269
- 功能说明:
195
+ description:
270
196
  获取所有可用的产品分类列表。
271
-
272
- 输入参数:
273
-
274
-
275
- 返回字段:
276
- data (dict): 产品分类信息
277
- - categories (list): 产品分类列表,如["subscription", "service", "addon"]
278
- success (bool): 操作是否成功
279
-
280
- 异常情况:
281
- - 获取产品分类失败:返回错误信息"获取产品分类失败"
197
+ return:
198
+ data(dict): 产品分类信息
199
+ - categories(list): 产品分类列表,如["subscription", "service", "addon"]
200
+ success(bool): 操作是否成功
282
201
  """
283
202
  data, success = await self._request("GET", "/api/products/categories/list")
284
203
  if not success:
@@ -1,16 +1,4 @@
1
- from .unified_login import (
2
- ThirdPartyAuthUrlRequest,
3
- ThirdPartyAuthUrlResponse,
4
- ThirdPartyLoginRequest,
5
- ThirdPartyLoginResponse,
6
- UnifiedLoginClientAsync,
7
- )
1
+ from .unified_login import GoogleLogin, WechatLogin, GitHubLogin
8
2
 
9
- __all__ = [
10
- "ThirdPartyAuthUrlRequest",
11
- "ThirdPartyAuthUrlResponse",
12
- "ThirdPartyLoginRequest",
13
- "ThirdPartyLoginResponse",
14
- "UnifiedLoginClientAsync",
15
- ]
3
+ __all__ = ["GoogleLogin", "WechatLogin", "GitHubLogin"]
16
4
 
@@ -1,18 +1,270 @@
1
- from client.pypi.pixelarraythirdparty.client import AsyncClient
1
+ import asyncio
2
+ import urllib.parse
3
+ import webbrowser
4
+ from typing import Dict, Optional, Tuple
5
+
6
+ from pixelarraythirdparty.client import AsyncClient
2
7
 
3
8
 
4
9
  class GoogleLogin(AsyncClient):
5
- async def _get_auth_url(self):
6
- pass
7
-
8
- async def _get_code_from_redirect_uri(self, redirect_uri: str):
9
- pass
10
+ """
11
+ Google OAuth2 登录客户端
12
+
13
+ 使用示例:
14
+ ```
15
+ google = GoogleLogin(api_key="your_api_key")
16
+ user_info, success = await google.login()
17
+ ```
18
+ """
19
+
20
+ def __init__(self, api_key: str):
21
+ super().__init__(api_key)
22
+
23
+ async def _get_auth_url(self) -> Tuple[Optional[Dict[str, str]], bool]:
24
+ data, success = await self._request(
25
+ "POST", "/api/unified-login/google/auth-url"
26
+ )
27
+ if not success:
28
+ return None, False
29
+ auth_url = data.get("auth_url")
30
+ if not auth_url:
31
+ return None, False
32
+ return data, True
33
+
34
+ async def login(self, timeout: int = 180) -> Tuple[Dict, bool]:
35
+ """
36
+ 仿 Supabase CLI 的一键登录流程:打开浏览器完成授权,
37
+ 终端端轮询等待登录结果
38
+
39
+ :param timeout: 等待用户完成授权的超时时间(秒)
40
+ """
41
+ auth_data, success = await self._get_auth_url()
42
+ if not success or not auth_data:
43
+ return {}, False
44
+
45
+ auth_url = auth_data.get("auth_url")
46
+ state = auth_data.get("state") or self._extract_state(auth_url)
47
+
48
+ if not auth_url or not state:
49
+ return {}, False
50
+
51
+ webbrowser.open(auth_url, new=2)
52
+
53
+ return await self._wait_for_google_login(state, timeout)
54
+
55
+ def _extract_state(self, auth_url: Optional[str]) -> Optional[str]:
56
+ if not auth_url:
57
+ return None
58
+ try:
59
+ parsed = urllib.parse.urlparse(auth_url)
60
+ query = urllib.parse.parse_qs(parsed.query)
61
+ values = query.get("state")
62
+ if values:
63
+ return values[0]
64
+ except Exception:
65
+ return None
66
+ return None
67
+
68
+ async def _wait_for_google_login(
69
+ self, state: str, timeout: int
70
+ ) -> Tuple[Dict, bool]:
71
+ interval = 2
72
+ total_checks = max(1, timeout // interval) if timeout > 0 else 1
73
+
74
+ for _ in range(total_checks):
75
+ status, response = await self._request_raw(
76
+ "POST",
77
+ "/api/unified-login/google/wait-login",
78
+ json={"state": state},
79
+ )
80
+
81
+ if status == 200 and response.get("success") is True:
82
+ return response.get("data", {}), True
83
+
84
+ if status in (400, 408):
85
+ break
86
+
87
+ await asyncio.sleep(interval)
88
+
89
+ return {}, False
90
+
91
+
92
+ class WechatLogin(AsyncClient):
93
+ """
94
+ 微信 OAuth2 登录客户端
95
+
96
+ 使用示例:
97
+ ```
98
+ wechat = WechatLogin(api_key="your_api_key")
99
+ user_info, success = await wechat.login()
100
+ ```
101
+ """
102
+
103
+ def __init__(self, api_key: str):
104
+ super().__init__(api_key)
105
+
106
+ async def _get_auth_url(self) -> Tuple[Optional[Dict[str, str]], bool]:
107
+ data, success = await self._request(
108
+ "POST", "/api/unified-login/wechat/auth-url"
109
+ )
110
+ if not success:
111
+ return None, False
112
+ auth_url = data.get("auth_url")
113
+ if not auth_url:
114
+ return None, False
115
+ return data, True
116
+
117
+ async def login(self, timeout: int = 180) -> Tuple[Dict, bool]:
118
+ """
119
+ 仿 Supabase CLI 的一键登录流程:打开浏览器完成授权,
120
+ 终端端轮询等待登录结果
121
+
122
+ :param timeout: 等待用户完成授权的超时时间(秒)
123
+ """
124
+ auth_data, success = await self._get_auth_url()
125
+ if not success or not auth_data:
126
+ return {}, False
127
+
128
+ auth_url = auth_data.get("auth_url")
129
+ state = auth_data.get("state") or self._extract_state(auth_url)
130
+
131
+ if not auth_url or not state:
132
+ return {}, False
133
+
134
+ webbrowser.open(auth_url, new=2)
135
+
136
+ return await self._wait_for_wechat_login(state, timeout)
137
+
138
+ def _extract_state(self, auth_url: Optional[str]) -> Optional[str]:
139
+ if not auth_url:
140
+ return None
141
+ try:
142
+ parsed = urllib.parse.urlparse(auth_url)
143
+ query = urllib.parse.parse_qs(parsed.query)
144
+ values = query.get("state")
145
+ if values:
146
+ return values[0]
147
+ except Exception:
148
+ return None
149
+ return None
150
+
151
+ async def _wait_for_wechat_login(
152
+ self, state: str, timeout: int
153
+ ) -> Tuple[Dict, bool]:
154
+ interval = 2
155
+ total_checks = max(1, timeout // interval) if timeout > 0 else 1
156
+
157
+ for _ in range(total_checks):
158
+ status, response = await self._request_raw(
159
+ "POST",
160
+ "/api/unified-login/wechat/wait-login",
161
+ json={"state": state},
162
+ )
163
+
164
+ if status == 200 and response.get("success") is True:
165
+ return response.get("data", {}), True
166
+
167
+ if status in (400, 408):
168
+ break
169
+
170
+ await asyncio.sleep(interval)
171
+
172
+ return {}, False
173
+
174
+
175
+ class GitHubLogin(AsyncClient):
176
+ """
177
+ GitHub OAuth2 登录客户端
178
+
179
+ 使用示例:
180
+ ```
181
+ github = GitHubLogin(api_key="your_api_key")
182
+ user_info, success = await github.login()
183
+ ```
184
+ """
185
+
186
+ def __init__(self, api_key: str):
187
+ super().__init__(api_key)
188
+
189
+ async def _get_auth_url(self) -> Tuple[Optional[Dict[str, str]], bool]:
190
+ data, success = await self._request(
191
+ "POST", "/api/unified-login/github/auth-url"
192
+ )
193
+ if not success:
194
+ return None, False
195
+ auth_url = data.get("auth_url")
196
+ if not auth_url:
197
+ return None, False
198
+ return data, True
199
+
200
+ async def login(self, timeout: int = 180) -> Tuple[Dict, bool]:
201
+ """
202
+ 仿 Supabase CLI 的一键登录流程:打开浏览器完成授权,
203
+ 终端端轮询等待登录结果
204
+
205
+ :param timeout: 等待用户完成授权的超时时间(秒)
206
+ """
207
+ auth_data, success = await self._get_auth_url()
208
+ if not success or not auth_data:
209
+ return {}, False
210
+
211
+ auth_url = auth_data.get("auth_url")
212
+ state = auth_data.get("state") or self._extract_state(auth_url)
213
+
214
+ if not auth_url or not state:
215
+ return {}, False
216
+
217
+ webbrowser.open(auth_url, new=2)
218
+
219
+ return await self._wait_for_github_login(state, timeout)
220
+
221
+ def _extract_state(self, auth_url: Optional[str]) -> Optional[str]:
222
+ if not auth_url:
223
+ return None
224
+ try:
225
+ parsed = urllib.parse.urlparse(auth_url)
226
+ query = urllib.parse.parse_qs(parsed.query)
227
+ values = query.get("state")
228
+ if values:
229
+ return values[0]
230
+ except Exception:
231
+ return None
232
+ return None
233
+
234
+ async def _wait_for_github_login(
235
+ self, state: str, timeout: int
236
+ ) -> Tuple[Dict, bool]:
237
+ interval = 2
238
+ total_checks = max(1, timeout // interval) if timeout > 0 else 1
239
+
240
+ for _ in range(total_checks):
241
+ status, response = await self._request_raw(
242
+ "POST",
243
+ "/api/unified-login/github/wait-login",
244
+ json={"state": state},
245
+ )
246
+
247
+ if status == 200 and response.get("success") is True:
248
+ return response.get("data", {}), True
249
+
250
+ if status in (400, 408):
251
+ break
252
+
253
+ await asyncio.sleep(interval)
254
+
255
+ return {}, False
10
256
 
11
- async def _get_user_info(self, token: str) -> dict:
12
- pass
13
257
 
14
- async def login(self) -> dict:
15
- pass
258
+ class UnifiedLogin(AsyncClient):
259
+ def __init__(self, api_key: str):
260
+ super().__init__(api_key)
16
261
 
17
- async def logout(self) -> dict:
18
- pass
262
+ async def login(self, provider: str, timeout: int = 180) -> Tuple[Dict, bool]:
263
+ if provider == "google":
264
+ return await GoogleLogin(self.api_key).login(timeout)
265
+ elif provider == "wechat":
266
+ return await WechatLogin(self.api_key).login(timeout)
267
+ elif provider == "github":
268
+ return await GitHubLogin(self.api_key).login(timeout)
269
+ else:
270
+ return {}, False