python-sandbox-sdk 1.0.0__tar.gz → 1.0.1__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.
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/PKG-INFO +4 -2
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/pyproject.toml +7 -2
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk/__init__.py +7 -1
- python_sandbox_sdk-1.0.1/python_sandbox_sdk/async_client.py +356 -0
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk.egg-info/PKG-INFO +4 -2
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk.egg-info/SOURCES.txt +2 -0
- python_sandbox_sdk-1.0.1/python_sandbox_sdk.egg-info/requires.txt +4 -0
- python_sandbox_sdk-1.0.0/python_sandbox_sdk.egg-info/requires.txt +0 -1
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/README.md +0 -0
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk/client.py +0 -0
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk/dto.py +0 -0
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk.egg-info/dependency_links.txt +0 -0
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk.egg-info/top_level.txt +0 -0
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/setup.cfg +0 -0
- {python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/setup.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-sandbox-sdk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Python SDK for Python Sandbox API - Run Python code, shell commands, and manage packages in Docker containers
|
|
5
5
|
Home-page: https://github.com/zjwan461/python-sandbox
|
|
6
|
-
Author-email:
|
|
6
|
+
Author-email: Jerry <826935261@qq.com>
|
|
7
7
|
License-Expression: MIT
|
|
8
8
|
Project-URL: Homepage, https://github.com/zjwan461/python-sandbox
|
|
9
9
|
Project-URL: Repository, https://github.com/zjwan461/python-sandbox
|
|
@@ -24,6 +24,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
24
24
|
Requires-Python: >=3.8
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
Requires-Dist: requests>=2.31.0
|
|
27
|
+
Provides-Extra: async
|
|
28
|
+
Requires-Dist: aiohttp>=3.9.0; extra == "async"
|
|
27
29
|
Dynamic: home-page
|
|
28
30
|
Dynamic: requires-python
|
|
29
31
|
|
|
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-sandbox-sdk"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.1"
|
|
8
8
|
description = "Python SDK for Python Sandbox API - Run Python code, shell commands, and manage packages in Docker containers"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
11
11
|
license = "MIT"
|
|
12
12
|
authors = [
|
|
13
|
-
{name = "
|
|
13
|
+
{name = "Jerry", email = "826935261@qq.com"}
|
|
14
14
|
]
|
|
15
15
|
keywords = ["sandbox", "docker", "python", "security", "shell"]
|
|
16
16
|
classifiers = [
|
|
@@ -29,6 +29,11 @@ dependencies = [
|
|
|
29
29
|
"requests>=2.31.0",
|
|
30
30
|
]
|
|
31
31
|
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
async = [
|
|
34
|
+
"aiohttp>=3.9.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
32
37
|
[project.urls]
|
|
33
38
|
Homepage = "https://github.com/zjwan461/python-sandbox"
|
|
34
39
|
Repository = "https://github.com/zjwan461/python-sandbox"
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
from .client import SandboxClient, SandboxError, ApiKeyMissingError, ApiRequestError
|
|
2
2
|
from .dto import CommandResult, SessionResponse
|
|
3
3
|
|
|
4
|
+
try:
|
|
5
|
+
from .async_client import AsyncSandboxClient
|
|
6
|
+
except ImportError:
|
|
7
|
+
AsyncSandboxClient = None
|
|
8
|
+
|
|
4
9
|
__all__ = [
|
|
5
10
|
'SandboxClient',
|
|
11
|
+
'AsyncSandboxClient',
|
|
6
12
|
'CommandResult',
|
|
7
13
|
'SessionResponse',
|
|
8
14
|
'SandboxError',
|
|
9
15
|
'ApiKeyMissingError',
|
|
10
16
|
'ApiRequestError',
|
|
11
17
|
]
|
|
12
|
-
__version__ = '1.0.
|
|
18
|
+
__version__ = '1.0.1'
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"""
|
|
2
|
+
异步 Python Sandbox 客户端
|
|
3
|
+
|
|
4
|
+
使用 aiohttp 提供与 SandboxClient 相同的 API,但所有方法均为 async。
|
|
5
|
+
|
|
6
|
+
使用示例:
|
|
7
|
+
>>> import asyncio
|
|
8
|
+
>>> from python_sandbox_sdk import AsyncSandboxClient
|
|
9
|
+
>>> async def main():
|
|
10
|
+
... async with AsyncSandboxClient("http://localhost:8080", "your-api-key") as client:
|
|
11
|
+
... session_id = await client.create_session()
|
|
12
|
+
... result = await client.exec_python(session_id, "print('Hello!')")
|
|
13
|
+
... print(result.stdout)
|
|
14
|
+
>>> asyncio.run(main())
|
|
15
|
+
Hello!
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import tempfile
|
|
20
|
+
from typing import Optional
|
|
21
|
+
|
|
22
|
+
import aiohttp
|
|
23
|
+
|
|
24
|
+
from .dto import CommandResult
|
|
25
|
+
from .client import SandboxError, ApiRequestError
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AsyncSandboxClient:
|
|
29
|
+
"""
|
|
30
|
+
异步 Python Sandbox 客户端
|
|
31
|
+
|
|
32
|
+
所有网络请求方法均为 async,支持 async with 上下文管理器。
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
base_url: Sandbox API 基础 URL (如 http://localhost:8080)
|
|
36
|
+
api_key: API 认证密钥
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
base_url: str,
|
|
42
|
+
api_key: str,
|
|
43
|
+
session: Optional[aiohttp.ClientSession] = None,
|
|
44
|
+
timeout: aiohttp.ClientTimeout = None,
|
|
45
|
+
):
|
|
46
|
+
"""
|
|
47
|
+
创建异步客户端实例
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
base_url: Sandbox API 基础 URL
|
|
51
|
+
api_key: API 认证密钥
|
|
52
|
+
session: 可选的自定义 aiohttp.ClientSession 实例
|
|
53
|
+
timeout: 默认请求超时(upload/download 有各自的超时)
|
|
54
|
+
"""
|
|
55
|
+
self.base_url = base_url.rstrip("/")
|
|
56
|
+
self.api_key = api_key
|
|
57
|
+
self._timeout = timeout or aiohttp.ClientTimeout(total=60)
|
|
58
|
+
self._external_session = session is not None
|
|
59
|
+
self._session: Optional[aiohttp.ClientSession] = session
|
|
60
|
+
|
|
61
|
+
async def _get_session(self) -> aiohttp.ClientSession:
|
|
62
|
+
"""获取或创建 aiohttp session(懒初始化)"""
|
|
63
|
+
if self._session is None or self._session.closed:
|
|
64
|
+
self._session = aiohttp.ClientSession(
|
|
65
|
+
headers={
|
|
66
|
+
"X-Api-Key": self.api_key,
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
},
|
|
69
|
+
timeout=self._timeout,
|
|
70
|
+
)
|
|
71
|
+
self._external_session = False
|
|
72
|
+
return self._session
|
|
73
|
+
|
|
74
|
+
# ==================== 会话管理 ====================
|
|
75
|
+
|
|
76
|
+
async def create_session(self) -> str:
|
|
77
|
+
"""
|
|
78
|
+
创建新的沙箱会话
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
会话 ID
|
|
82
|
+
"""
|
|
83
|
+
session = await self._get_session()
|
|
84
|
+
async with session.post(f"{self.base_url}/api/sandbox/session") as resp:
|
|
85
|
+
await self._raise_if_error(resp)
|
|
86
|
+
data = await resp.json()
|
|
87
|
+
return data["sessionId"]
|
|
88
|
+
|
|
89
|
+
async def delete_session(self, session_id: str) -> None:
|
|
90
|
+
"""
|
|
91
|
+
删除会话并清理容器
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
session_id: 会话 ID
|
|
95
|
+
"""
|
|
96
|
+
session = await self._get_session()
|
|
97
|
+
url = f"{self.base_url}/api/sandbox/session/{session_id}"
|
|
98
|
+
async with session.delete(url) as resp:
|
|
99
|
+
await self._raise_if_error(resp)
|
|
100
|
+
|
|
101
|
+
# ==================== 代码执行 ====================
|
|
102
|
+
|
|
103
|
+
async def exec_python(self, session_id: str, code: str) -> CommandResult:
|
|
104
|
+
"""
|
|
105
|
+
在沙箱中执行 Python 代码
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
session_id: 会话 ID
|
|
109
|
+
code: Python 源代码
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
命令执行结果
|
|
113
|
+
"""
|
|
114
|
+
payload = {"sessionId": session_id, "code": code}
|
|
115
|
+
session = await self._get_session()
|
|
116
|
+
async with session.post(
|
|
117
|
+
f"{self.base_url}/api/sandbox/exec/python", json=payload
|
|
118
|
+
) as resp:
|
|
119
|
+
await self._raise_if_error(resp)
|
|
120
|
+
data = await resp.json()
|
|
121
|
+
return CommandResult(
|
|
122
|
+
data["exitCode"], data.get("stdout", ""), data.get("stderr", "")
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
async def exec_shell(self, session_id: str, command: str) -> CommandResult:
|
|
126
|
+
"""
|
|
127
|
+
在沙箱中执行 Shell 命令
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
session_id: 会话 ID
|
|
131
|
+
command: Shell 命令
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
命令执行结果
|
|
135
|
+
"""
|
|
136
|
+
payload = {"sessionId": session_id, "command": command}
|
|
137
|
+
session = await self._get_session()
|
|
138
|
+
async with session.post(
|
|
139
|
+
f"{self.base_url}/api/sandbox/exec/shell", json=payload
|
|
140
|
+
) as resp:
|
|
141
|
+
await self._raise_if_error(resp)
|
|
142
|
+
data = await resp.json()
|
|
143
|
+
return CommandResult(
|
|
144
|
+
data["exitCode"], data.get("stdout", ""), data.get("stderr", "")
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# ==================== pip 包管理 ====================
|
|
148
|
+
|
|
149
|
+
async def pip_install(self, session_id: str, package_name: str) -> CommandResult:
|
|
150
|
+
"""
|
|
151
|
+
安装 Python 包
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
session_id: 会话 ID
|
|
155
|
+
package_name: 包名(支持版本约束)
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
命令执行结果
|
|
159
|
+
"""
|
|
160
|
+
payload = {"sessionId": session_id, "pkg": package_name}
|
|
161
|
+
session = await self._get_session()
|
|
162
|
+
async with session.post(
|
|
163
|
+
f"{self.base_url}/api/sandbox/pip/install", json=payload
|
|
164
|
+
) as resp:
|
|
165
|
+
await self._raise_if_error(resp)
|
|
166
|
+
data = await resp.json()
|
|
167
|
+
return CommandResult(
|
|
168
|
+
data["exitCode"], data.get("stdout", ""), data.get("stderr", "")
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
async def pip_uninstall(
|
|
172
|
+
self, session_id: str, package_name: str
|
|
173
|
+
) -> CommandResult:
|
|
174
|
+
"""
|
|
175
|
+
卸载 Python 包
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
session_id: 会话 ID
|
|
179
|
+
package_name: 包名
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
命令执行结果
|
|
183
|
+
"""
|
|
184
|
+
payload = {"sessionId": session_id, "pkg": package_name}
|
|
185
|
+
session = await self._get_session()
|
|
186
|
+
async with session.post(
|
|
187
|
+
f"{self.base_url}/api/sandbox/pip/uninstall", json=payload
|
|
188
|
+
) as resp:
|
|
189
|
+
await self._raise_if_error(resp)
|
|
190
|
+
data = await resp.json()
|
|
191
|
+
return CommandResult(
|
|
192
|
+
data["exitCode"], data.get("stdout", ""), data.get("stderr", "")
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
async def pip_list(self, session_id: str) -> str:
|
|
196
|
+
"""
|
|
197
|
+
列出已安装的 Python 包
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
session_id: 会话 ID
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
安装包列表文本
|
|
204
|
+
"""
|
|
205
|
+
session = await self._get_session()
|
|
206
|
+
async with session.get(
|
|
207
|
+
f"{self.base_url}/api/sandbox/pip/list",
|
|
208
|
+
params={"sessionId": session_id},
|
|
209
|
+
) as resp:
|
|
210
|
+
await self._raise_if_error(resp)
|
|
211
|
+
data = await resp.json()
|
|
212
|
+
return data["packages"]
|
|
213
|
+
|
|
214
|
+
# ==================== 文件操作 ====================
|
|
215
|
+
|
|
216
|
+
async def write_file(
|
|
217
|
+
self, session_id: str, container_path: str, content: str
|
|
218
|
+
) -> None:
|
|
219
|
+
"""
|
|
220
|
+
向沙箱写入文件内容
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
session_id: 会话 ID
|
|
224
|
+
container_path: 容器内目标路径
|
|
225
|
+
content: 文件内容
|
|
226
|
+
"""
|
|
227
|
+
payload = {
|
|
228
|
+
"sessionId": session_id,
|
|
229
|
+
"path": container_path,
|
|
230
|
+
"content": content,
|
|
231
|
+
}
|
|
232
|
+
session = await self._get_session()
|
|
233
|
+
async with session.post(
|
|
234
|
+
f"{self.base_url}/api/sandbox/file/write", json=payload
|
|
235
|
+
) as resp:
|
|
236
|
+
await self._raise_if_error(resp)
|
|
237
|
+
|
|
238
|
+
async def read_file(self, session_id: str, container_path: str) -> str:
|
|
239
|
+
"""
|
|
240
|
+
读取沙箱中的文件内容
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
session_id: 会话 ID
|
|
244
|
+
container_path: 容器内文件路径
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
文件内容字符串
|
|
248
|
+
"""
|
|
249
|
+
session = await self._get_session()
|
|
250
|
+
async with session.get(
|
|
251
|
+
f"{self.base_url}/api/sandbox/file/read",
|
|
252
|
+
params={"sessionId": session_id, "path": container_path},
|
|
253
|
+
) as resp:
|
|
254
|
+
await self._raise_if_error(resp)
|
|
255
|
+
data = await resp.json()
|
|
256
|
+
return data["content"]
|
|
257
|
+
|
|
258
|
+
async def upload_file(
|
|
259
|
+
self, session_id: str, container_path: str, data: bytes
|
|
260
|
+
) -> None:
|
|
261
|
+
"""
|
|
262
|
+
上传二进制文件到沙箱
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
session_id: 会话 ID
|
|
266
|
+
container_path: 容器内目标路径
|
|
267
|
+
data: 文件字节数据
|
|
268
|
+
"""
|
|
269
|
+
# 写入临时文件
|
|
270
|
+
fd, tmp_path = tempfile.mkstemp(prefix="sandbox_upload_")
|
|
271
|
+
try:
|
|
272
|
+
with os.fdopen(fd, "wb") as f:
|
|
273
|
+
f.write(data)
|
|
274
|
+
|
|
275
|
+
url = f"{self.base_url}/api/sandbox/file/upload"
|
|
276
|
+
form = aiohttp.FormData()
|
|
277
|
+
form.add_field(
|
|
278
|
+
"file",
|
|
279
|
+
open(tmp_path, "rb"),
|
|
280
|
+
filename=os.path.basename(container_path),
|
|
281
|
+
)
|
|
282
|
+
form.add_field("sessionId", session_id)
|
|
283
|
+
form.add_field("path", container_path)
|
|
284
|
+
|
|
285
|
+
# 上传使用独立的 session,避免继承主 session 的 Content-Type
|
|
286
|
+
upload_timeout = aiohttp.ClientTimeout(total=120)
|
|
287
|
+
async with aiohttp.ClientSession(timeout=upload_timeout) as upload_session:
|
|
288
|
+
upload_session.headers.update({"X-Api-Key": self.api_key})
|
|
289
|
+
async with upload_session.post(url, data=form) as resp:
|
|
290
|
+
await self._raise_if_error(resp)
|
|
291
|
+
finally:
|
|
292
|
+
if os.path.exists(tmp_path):
|
|
293
|
+
os.unlink(tmp_path)
|
|
294
|
+
|
|
295
|
+
async def download_file(self, session_id: str, container_path: str) -> bytes:
|
|
296
|
+
"""
|
|
297
|
+
下载沙箱中的文件
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
session_id: 会话 ID
|
|
301
|
+
container_path: 容器内文件路径
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
文件字节数据
|
|
305
|
+
"""
|
|
306
|
+
url = f"{self.base_url}/api/sandbox/file/download"
|
|
307
|
+
params = {"sessionId": session_id, "path": container_path}
|
|
308
|
+
|
|
309
|
+
download_timeout = aiohttp.ClientTimeout(total=60)
|
|
310
|
+
async with aiohttp.ClientSession(timeout=download_timeout) as s:
|
|
311
|
+
s.headers.update({"X-Api-Key": self.api_key})
|
|
312
|
+
async with s.get(url, params=params) as resp:
|
|
313
|
+
await self._raise_if_error(resp)
|
|
314
|
+
return await resp.read()
|
|
315
|
+
|
|
316
|
+
# ==================== 健康检查 ====================
|
|
317
|
+
|
|
318
|
+
async def is_health(self) -> bool:
|
|
319
|
+
"""
|
|
320
|
+
检查沙箱服务是否可用
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
True 如果服务正常运行
|
|
324
|
+
"""
|
|
325
|
+
try:
|
|
326
|
+
health_timeout = aiohttp.ClientTimeout(total=5)
|
|
327
|
+
async with aiohttp.ClientSession(timeout=health_timeout) as s:
|
|
328
|
+
async with s.get(f"{self.base_url}/health") as resp:
|
|
329
|
+
return resp.status == 200
|
|
330
|
+
except Exception:
|
|
331
|
+
return False
|
|
332
|
+
|
|
333
|
+
# ==================== 内部方法 ====================
|
|
334
|
+
|
|
335
|
+
@staticmethod
|
|
336
|
+
async def _raise_if_error(resp: aiohttp.ClientResponse) -> None:
|
|
337
|
+
"""如果响应状态码表示错误则抛出异常"""
|
|
338
|
+
if resp.status >= 400:
|
|
339
|
+
try:
|
|
340
|
+
error_data = await resp.json()
|
|
341
|
+
message = error_data.get("message", await resp.text())
|
|
342
|
+
except Exception:
|
|
343
|
+
message = await resp.text()
|
|
344
|
+
raise ApiRequestError(resp.status, message)
|
|
345
|
+
|
|
346
|
+
async def close(self) -> None:
|
|
347
|
+
"""关闭 HTTP 会话(仅关闭内部创建的 session)"""
|
|
348
|
+
if self._session and not self._external_session:
|
|
349
|
+
await self._session.close()
|
|
350
|
+
self._session = None
|
|
351
|
+
|
|
352
|
+
async def __aenter__(self):
|
|
353
|
+
return self
|
|
354
|
+
|
|
355
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
356
|
+
await self.close()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-sandbox-sdk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Python SDK for Python Sandbox API - Run Python code, shell commands, and manage packages in Docker containers
|
|
5
5
|
Home-page: https://github.com/zjwan461/python-sandbox
|
|
6
|
-
Author-email:
|
|
6
|
+
Author-email: Jerry <826935261@qq.com>
|
|
7
7
|
License-Expression: MIT
|
|
8
8
|
Project-URL: Homepage, https://github.com/zjwan461/python-sandbox
|
|
9
9
|
Project-URL: Repository, https://github.com/zjwan461/python-sandbox
|
|
@@ -24,6 +24,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
24
24
|
Requires-Python: >=3.8
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
Requires-Dist: requests>=2.31.0
|
|
27
|
+
Provides-Extra: async
|
|
28
|
+
Requires-Dist: aiohttp>=3.9.0; extra == "async"
|
|
27
29
|
Dynamic: home-page
|
|
28
30
|
Dynamic: requires-python
|
|
29
31
|
|
{python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk.egg-info/SOURCES.txt
RENAMED
|
@@ -2,9 +2,11 @@ README.md
|
|
|
2
2
|
pyproject.toml
|
|
3
3
|
setup.py
|
|
4
4
|
./python_sandbox_sdk/__init__.py
|
|
5
|
+
./python_sandbox_sdk/async_client.py
|
|
5
6
|
./python_sandbox_sdk/client.py
|
|
6
7
|
./python_sandbox_sdk/dto.py
|
|
7
8
|
python_sandbox_sdk/__init__.py
|
|
9
|
+
python_sandbox_sdk/async_client.py
|
|
8
10
|
python_sandbox_sdk/client.py
|
|
9
11
|
python_sandbox_sdk/dto.py
|
|
10
12
|
python_sandbox_sdk.egg-info/PKG-INFO
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
requests>=2.31.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_sandbox_sdk-1.0.0 → python_sandbox_sdk-1.0.1}/python_sandbox_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|