modelscope-api 0.0.4__tar.gz → 0.0.5__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.
- {modelscope_api-0.0.4/src/modelscope_api.egg-info → modelscope_api-0.0.5}/PKG-INFO +1 -1
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/pyproject.toml +1 -1
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/modelscope_client.py +19 -1
- {modelscope_api-0.0.4 → modelscope_api-0.0.5/src/modelscope_api.egg-info}/PKG-INFO +1 -1
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api.egg-info/SOURCES.txt +2 -1
- modelscope_api-0.0.5/tests/test_stream.py +125 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/LICENSE +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/README.md +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/setup.cfg +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/config.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/base.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/collection/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/collection/collection.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/collection/collection_item.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/magicube/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/magicube/magicube_blance.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/base_image.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/environment_variable.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/hardware.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/logs.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/sdk.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/studio.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/user/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/user/user.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/exceptions.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/_sub_client.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/collection/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/collection/collection.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/collection/collection_client.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/collection/collection_item.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/collection/collection_item_client.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/magicube/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/magicube/magicube_client.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/studio/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/studio/environment_variable_client.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/studio/studio.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/studio/studio_client.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/user/__init__.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/user/user_client.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/utils/regex.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/utils/typing.py +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api.egg-info/dependency_links.txt +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api.egg-info/requires.txt +0 -0
- {modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "modelscope-api" # 包名,保持与项目仓库名一致
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.5" # 当前版本
|
|
8
8
|
description = "A Python async SDK that wraps the ModelScope API into a clean, type-safe interface." # 简短描述
|
|
9
9
|
readme = "README.md" # 自述文件,PyPI 会将其渲染为项目首页
|
|
10
10
|
authors = [{name = "Jerry", email = "wujr24@m.fudan.edu.cn"}] # 作者信息
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/modelscope_client.py
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
-
from typing import Any, Dict, List, Optional, Union
|
|
6
|
+
from typing import Any, AsyncContextManager, Dict, List, Optional, Union
|
|
7
7
|
|
|
8
8
|
from fake_useragent import UserAgent
|
|
9
9
|
import httpx
|
|
@@ -201,6 +201,24 @@ class ModelScopeClient:
|
|
|
201
201
|
return response
|
|
202
202
|
|
|
203
203
|
|
|
204
|
+
def stream(self, **kwargs) -> AsyncContextManager[httpx.Response]:
|
|
205
|
+
"""
|
|
206
|
+
用该客户端发送流式请求。
|
|
207
|
+
|
|
208
|
+
用法与 `httpx.AsyncClient.stream` 完全一致,区别在于发送前会通过
|
|
209
|
+
`self._get_kwargs` 合并本客户端初始化时的 `self._kwargs`(以及 API Token)。
|
|
210
|
+
|
|
211
|
+
用法:
|
|
212
|
+
async with client.stream(method="GET", url=url) as response:
|
|
213
|
+
async for chunk in response.aiter_bytes():
|
|
214
|
+
...
|
|
215
|
+
|
|
216
|
+
注意:该方法不是协程,直接返回异步上下文管理器,使用时无需 `await`。
|
|
217
|
+
"""
|
|
218
|
+
kwargs = self._get_kwargs(kwargs)
|
|
219
|
+
return self._http_client.stream(**kwargs)
|
|
220
|
+
|
|
221
|
+
|
|
204
222
|
async def request_data(
|
|
205
223
|
self,
|
|
206
224
|
*,
|
|
@@ -42,4 +42,5 @@ src/modelscope_api/models/studio/studio_client.py
|
|
|
42
42
|
src/modelscope_api/models/user/__init__.py
|
|
43
43
|
src/modelscope_api/models/user/user_client.py
|
|
44
44
|
src/modelscope_api/utils/regex.py
|
|
45
|
-
src/modelscope_api/utils/typing.py
|
|
45
|
+
src/modelscope_api/utils/typing.py
|
|
46
|
+
tests/test_stream.py
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`ModelScopeClient.stream` 的测试用例。
|
|
3
|
+
|
|
4
|
+
通过 `httpx.MockTransport` 伪造网络请求,无需真实网络与 API Token。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
|
|
11
|
+
from modelscope_api import ModelScopeClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _run(coro):
|
|
15
|
+
return asyncio.run(coro)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_stream_merges_init_kwargs():
|
|
19
|
+
"""
|
|
20
|
+
初始化客户端时传入的 kwargs 应被合并进流式请求。
|
|
21
|
+
"""
|
|
22
|
+
async def main():
|
|
23
|
+
received = {}
|
|
24
|
+
|
|
25
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
26
|
+
received["headers"] = dict(request.headers)
|
|
27
|
+
received["url"] = str(request.url)
|
|
28
|
+
return httpx.Response(200, content=b"hello world")
|
|
29
|
+
|
|
30
|
+
transport = httpx.MockTransport(handler)
|
|
31
|
+
http_client = httpx.AsyncClient(transport=transport)
|
|
32
|
+
|
|
33
|
+
client = ModelScopeClient(
|
|
34
|
+
api_key="", # 避免读取环境变量中的 Token
|
|
35
|
+
http_client=http_client,
|
|
36
|
+
headers={
|
|
37
|
+
"user-agent": "test-agent", # 避免动态生成 UA
|
|
38
|
+
"X-Injected": "from-init",
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
async with client.stream(method="GET", url="https://example.com/echo") as response:
|
|
43
|
+
assert response.status_code == 200
|
|
44
|
+
chunks = [chunk async for chunk in response.aiter_bytes()]
|
|
45
|
+
|
|
46
|
+
assert b"".join(chunks) == b"hello world"
|
|
47
|
+
assert received["url"] == "https://example.com/echo"
|
|
48
|
+
assert received["headers"]["x-injected"] == "from-init"
|
|
49
|
+
assert received["headers"]["user-agent"] == "test-agent"
|
|
50
|
+
|
|
51
|
+
await http_client.aclose()
|
|
52
|
+
|
|
53
|
+
_run(main())
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_stream_call_kwargs_override_init_kwargs():
|
|
57
|
+
"""
|
|
58
|
+
调用 stream 时传入的 kwargs 应覆盖初始化时的 kwargs。
|
|
59
|
+
"""
|
|
60
|
+
async def main():
|
|
61
|
+
received = {}
|
|
62
|
+
|
|
63
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
64
|
+
received["headers"] = dict(request.headers)
|
|
65
|
+
return httpx.Response(200, content=b"ok")
|
|
66
|
+
|
|
67
|
+
transport = httpx.MockTransport(handler)
|
|
68
|
+
http_client = httpx.AsyncClient(transport=transport)
|
|
69
|
+
|
|
70
|
+
client = ModelScopeClient(
|
|
71
|
+
api_key="",
|
|
72
|
+
http_client=http_client,
|
|
73
|
+
headers={"user-agent": "test-agent", "X-Test": "init"},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
async with client.stream(
|
|
77
|
+
method="POST",
|
|
78
|
+
url="https://example.com/echo",
|
|
79
|
+
headers={"X-Test": "call"},
|
|
80
|
+
content=b"body",
|
|
81
|
+
) as response:
|
|
82
|
+
await response.aread()
|
|
83
|
+
|
|
84
|
+
assert received["headers"]["x-test"] == "call"
|
|
85
|
+
|
|
86
|
+
await http_client.aclose()
|
|
87
|
+
|
|
88
|
+
_run(main())
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_stream_injects_api_key():
|
|
92
|
+
"""
|
|
93
|
+
流式请求应携带 API Token 的 Authorization 头。
|
|
94
|
+
"""
|
|
95
|
+
async def main():
|
|
96
|
+
received = {}
|
|
97
|
+
|
|
98
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
99
|
+
received["headers"] = dict(request.headers)
|
|
100
|
+
return httpx.Response(200, content=b"ok")
|
|
101
|
+
|
|
102
|
+
transport = httpx.MockTransport(handler)
|
|
103
|
+
http_client = httpx.AsyncClient(transport=transport)
|
|
104
|
+
|
|
105
|
+
client = ModelScopeClient(
|
|
106
|
+
api_key="test-key",
|
|
107
|
+
http_client=http_client,
|
|
108
|
+
headers={"user-agent": "test-agent"},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
async with client.stream(method="GET", url="https://example.com/echo") as response:
|
|
112
|
+
await response.aread()
|
|
113
|
+
|
|
114
|
+
assert received["headers"]["authorization"] == "Bearer test-key"
|
|
115
|
+
|
|
116
|
+
await http_client.aclose()
|
|
117
|
+
|
|
118
|
+
_run(main())
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
test_stream_merges_init_kwargs()
|
|
123
|
+
test_stream_call_kwargs_override_init_kwargs()
|
|
124
|
+
test_stream_injects_api_key()
|
|
125
|
+
print("All stream tests passed.")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/collection/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/magicube/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/__init__.py
RENAMED
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/base_image.py
RENAMED
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/hardware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/studio/studio.py
RENAMED
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/data_models/user/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/collection/__init__.py
RENAMED
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/collection/collection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/magicube/__init__.py
RENAMED
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/magicube/magicube_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api/models/studio/studio_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_api-0.0.4 → modelscope_api-0.0.5}/src/modelscope_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|