spaces 0.51.3__tar.gz → 0.52.0.dev0__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.
Files changed (77) hide show
  1. {spaces-0.51.3 → spaces-0.52.0.dev0}/PKG-INFO +4 -3
  2. {spaces-0.51.3 → spaces-0.52.0.dev0}/pyproject.toml +19 -12
  3. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/__init__.py +13 -4
  4. spaces-0.52.0.dev0/spaces/_vendor/asgiref/typing.py +279 -0
  5. spaces-0.52.0.dev0/spaces/_vendor/sse_starlette/py.typed +0 -0
  6. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/config.py +0 -2
  7. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/reloading/__init__.py +6 -2
  8. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/reloading/server.py +5 -0
  9. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/utils.py +5 -12
  10. spaces-0.52.0.dev0/spaces/zero/__init__.py +46 -0
  11. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/client.py +86 -94
  12. spaces-0.52.0.dev0/spaces/zero/context.py +122 -0
  13. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/decorator.py +2 -3
  14. spaces-0.52.0.dev0/spaces/zero/gradio.py +171 -0
  15. spaces-0.52.0.dev0/spaces/zero/lifecycle.py +50 -0
  16. spaces-0.52.0.dev0/spaces/zero/middleware.py +112 -0
  17. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/patching.py +1 -4
  18. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/types.py +18 -10
  19. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/wrappers.py +72 -99
  20. spaces-0.51.3/spaces/gradio.py +0 -53
  21. spaces-0.51.3/spaces/zero/__init__.py +0 -41
  22. spaces-0.51.3/spaces/zero/gradio.py +0 -188
  23. {spaces-0.51.3 → spaces-0.52.0.dev0}/README.md +0 -0
  24. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/__init__.py +0 -0
  25. /spaces-0.51.3/spaces/_vendor/ovld/py.typed → /spaces-0.52.0.dev0/spaces/_vendor/asgiref/__init__.py +0 -0
  26. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/codefind/LICENSE +0 -0
  27. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/codefind/__init__.py +0 -0
  28. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/codefind/registry.py +0 -0
  29. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/codefind/version.py +0 -0
  30. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/jurigged/LICENSE +0 -0
  31. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/jurigged/__init__.py +0 -0
  32. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/jurigged/codetools.py +0 -0
  33. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/jurigged/parse.py +0 -0
  34. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/jurigged/register.py +0 -0
  35. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/jurigged/utils.py +0 -0
  36. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/jurigged/version.py +0 -0
  37. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/LICENSE +0 -0
  38. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/__init__.py +0 -0
  39. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/abc.py +0 -0
  40. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/codegen.py +0 -0
  41. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/core.py +0 -0
  42. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/dependent.py +0 -0
  43. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/medley.py +0 -0
  44. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/mro.py +0 -0
  45. {spaces-0.51.3/spaces/_vendor/sse_starlette → spaces-0.52.0.dev0/spaces/_vendor/ovld}/py.typed +0 -0
  46. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/recode.py +0 -0
  47. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/signatures.py +0 -0
  48. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/typemap.py +0 -0
  49. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/types.py +0 -0
  50. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/utils.py +0 -0
  51. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/ovld/version.py +0 -0
  52. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/sse_starlette/LICENSE +0 -0
  53. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/sse_starlette/__init__.py +0 -0
  54. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/sse_starlette/event.py +0 -0
  55. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/sse_starlette/sse.py +0 -0
  56. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/sseclient/LICENSE +0 -0
  57. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/_vendor/sseclient/__init__.py +0 -0
  58. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/reloading/client.py +0 -0
  59. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/reloading/types.py +0 -0
  60. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/reloading/types.ts +0 -0
  61. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/api.py +0 -0
  62. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/config.py +0 -0
  63. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/configs.json +0 -0
  64. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/elf.py +0 -0
  65. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/mmap.py +0 -0
  66. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/__init__.py +0 -0
  67. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/aoti.py +0 -0
  68. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/bitsandbytes.py +0 -0
  69. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/bitsandbytes_legacy.py +0 -0
  70. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/cudart.py +0 -0
  71. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/packing.py +0 -0
  72. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/patching_legacy.py +0 -0
  73. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/static.py +0 -0
  74. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/types.py +0 -0
  75. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/torch/utils.py +0 -0
  76. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/tqdm.py +0 -0
  77. {spaces-0.51.3 → spaces-0.52.0.dev0}/spaces/zero/utils.py +0 -0
@@ -1,19 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spaces
3
- Version: 0.51.3
3
+ Version: 0.52.0.dev0
4
4
  Summary: Utilities for Hugging Face Spaces
5
5
  Author: Charles Bensimon
6
6
  Author-email: Charles Bensimon <charles@huggingface.co>
7
7
  License-Expression: Apache-2.0
8
8
  Requires-Dist: packaging
9
9
  Requires-Dist: typing-extensions>=4,<5
10
- Requires-Dist: requests>=2.19,<3
11
- Requires-Dist: gradio
12
10
  Requires-Dist: pydantic>=1,<3
13
11
  Requires-Dist: httpx>=0.20
12
+ Requires-Dist: fastapi ; extra == 'serving'
13
+ Requires-Dist: uvicorn ; extra == 'serving'
14
14
  Requires-Python: >=3.10, <3.15
15
15
  Project-URL: Homepage, https://huggingface.co
16
16
  Project-URL: Repository, https://github.com/huggingface/huggingface_hub
17
+ Provides-Extra: serving
17
18
  Description-Content-Type: text/markdown
18
19
 
19
20
  # Hugging Face Spaces
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "spaces"
3
- version = "0.51.3"
3
+ version = "0.52.0.dev0"
4
4
  description = "Utilities for Hugging Face Spaces"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.15"
@@ -11,12 +11,16 @@ authors = [
11
11
  dependencies = [
12
12
  "packaging",
13
13
  "typing-extensions>=4,<5",
14
- "requests>=2.19,<3",
15
- "gradio", # Actually requires 3.2+ if for `@spaces.GPU`
16
14
  "pydantic>=1,<3",
17
15
  "httpx>=0.20",
18
16
  ]
19
17
 
18
+ [project.optional-dependencies]
19
+ serving = [
20
+ "fastapi",
21
+ "uvicorn"
22
+ ]
23
+
20
24
  [project.urls]
21
25
  Homepage = "https://huggingface.co"
22
26
  Repository = "https://github.com/huggingface/huggingface_hub"
@@ -26,20 +30,20 @@ dev = [
26
30
  "pytest>=7.3.1,<8",
27
31
  "pytest-dotenv>=0.5.2,<0.6",
28
32
  "pytest-mock>=3.10.0,<4",
29
- "requests-mock>=1.10.0,<2",
30
33
  "pytest-timeout>=2.1.0,<3",
31
34
  "poethepoet>=0.20.0,<0.21",
32
35
  "coverage>=7.2.6,<8",
33
36
  "pyright>=1.1.403,<2",
34
37
  "pytest-order>=1.1.0,<2",
35
38
  "pynvml>=11.5.0,<12",
36
- "websockets>=13.0,<14",
37
39
  "pytest-asyncio>=0.21.1,<0.22",
38
40
  "pytest-httpx>=0.27.0,<0.28",
39
41
  "pydantic-to-typescript>=2.0.0,<3",
42
+ "requests>=2.19,<3",
40
43
  "setuptools",
41
44
  ]
42
45
  test = [
46
+ "gradio",
43
47
  "diffusers",
44
48
  "transformers",
45
49
  "accelerate",
@@ -51,6 +55,13 @@ test = [
51
55
  "kernels>=0.10.2,<0.11",
52
56
  ]
53
57
 
58
+ [tool.uv]
59
+ constraint-dependencies = [
60
+ "numpy<2",
61
+ "peft<0.19",
62
+ "transformers<4.51",
63
+ ]
64
+
54
65
  [tool.pytest.ini_options]
55
66
  addopts = "-v --durations=0 --durations-min=1"
56
67
  testpaths = ["tests"]
@@ -83,6 +94,8 @@ shell = """set -e
83
94
  coverage run -m pytest tests/cpu
84
95
  coverage run -m pytest tests/gpu
85
96
  find e2e -name '*.py' | xargs -I {} coverage run {}
97
+ pytest tests/cpu/serving/test_middleware.py::test_fds_server_hang --fd-xfail
98
+ pytest tests/cpu/serving/test_middleware.py::test_fds_requests_hang --fd-xfail
86
99
  coverage combine -q
87
100
  coverage xml || true
88
101
  coverage html || true
@@ -101,17 +114,11 @@ shell = """set -e
101
114
  include = ["spaces", "tests"]
102
115
  exclude = ["spaces/_vendor"]
103
116
  pythonVersion = "3.10"
117
+ reportMatchNotExhaustive = "error"
104
118
  reportPossiblyUnboundVariable = "error"
105
119
  reportUnnecessaryComparison = true
106
120
  reportPrivateImportUsage = "information"
107
121
 
108
- [tool.uv]
109
- constraint-dependencies = [
110
- "numpy<2",
111
- "peft<0.19",
112
- "transformers<4.51",
113
- ]
114
-
115
122
  [build-system]
116
123
  requires = ["uv_build>=0.11.6,<0.12"]
117
124
  build-backend = "uv_build"
@@ -1,12 +1,14 @@
1
1
  """
2
2
  """
3
+
3
4
  import sys
5
+ import warnings
4
6
  from types import FunctionType
5
7
  from typing import TYPE_CHECKING
6
8
  from typing import Callable
7
9
 
8
10
 
9
- # Prevent gradio from importing spaces
11
+ # Prevent partially-imported gradio from importing spaces
10
12
  if (gr := sys.modules.get('gradio')) is not None: # pragma: no cover
11
13
  try:
12
14
  gr.Blocks
@@ -15,9 +17,16 @@ if (gr := sys.modules.get('gradio')) is not None: # pragma: no cover
15
17
 
16
18
 
17
19
  from .zero.decorator import GPU
18
- from .gradio import gradio_auto_wrap
19
- from .gradio import disable_gradio_auto_wrap
20
- from .gradio import enable_gradio_auto_wrap
20
+
21
+
22
+ def gradio_auto_wrap(*args, **kwargs): # pragma: no cover
23
+ warnings.warn("gradio_auto_wrap has no effect and is deprecated")
24
+
25
+ def disable_gradio_auto_wrap(*args, **kwargs): # pragma: no cover
26
+ warnings.warn("gradio_auto_wrap has no effect and is deprecated")
27
+
28
+ def enable_gradio_auto_wrap(*args, **kwargs): # pragma: no cover
29
+ warnings.warn("gradio_auto_wrap has no effect and is deprecated")
21
30
 
22
31
 
23
32
  class LazyImported:
@@ -0,0 +1,279 @@
1
+ import sys
2
+ from typing import (
3
+ Any,
4
+ Awaitable,
5
+ Callable,
6
+ Dict,
7
+ Iterable,
8
+ Literal,
9
+ Optional,
10
+ Protocol,
11
+ Tuple,
12
+ Type,
13
+ TypedDict,
14
+ Union,
15
+ )
16
+
17
+ if sys.version_info >= (3, 11):
18
+ from typing import NotRequired
19
+ else:
20
+ from typing_extensions import NotRequired
21
+
22
+ __all__ = (
23
+ "ASGIVersions",
24
+ "HTTPScope",
25
+ "WebSocketScope",
26
+ "LifespanScope",
27
+ "WWWScope",
28
+ "Scope",
29
+ "HTTPRequestEvent",
30
+ "HTTPResponseStartEvent",
31
+ "HTTPResponseBodyEvent",
32
+ "HTTPResponseTrailersEvent",
33
+ "HTTPResponsePathsendEvent",
34
+ "HTTPServerPushEvent",
35
+ "HTTPDisconnectEvent",
36
+ "WebSocketConnectEvent",
37
+ "WebSocketAcceptEvent",
38
+ "WebSocketReceiveEvent",
39
+ "WebSocketSendEvent",
40
+ "WebSocketResponseStartEvent",
41
+ "WebSocketResponseBodyEvent",
42
+ "WebSocketDisconnectEvent",
43
+ "WebSocketCloseEvent",
44
+ "LifespanStartupEvent",
45
+ "LifespanShutdownEvent",
46
+ "LifespanStartupCompleteEvent",
47
+ "LifespanStartupFailedEvent",
48
+ "LifespanShutdownCompleteEvent",
49
+ "LifespanShutdownFailedEvent",
50
+ "ASGIReceiveEvent",
51
+ "ASGISendEvent",
52
+ "ASGIReceiveCallable",
53
+ "ASGISendCallable",
54
+ "ASGI2Protocol",
55
+ "ASGI2Application",
56
+ "ASGI3Application",
57
+ "ASGIApplication",
58
+ )
59
+
60
+
61
+ class ASGIVersions(TypedDict):
62
+ spec_version: str
63
+ version: Union[Literal["2.0"], Literal["3.0"]]
64
+
65
+
66
+ class HTTPScope(TypedDict):
67
+ type: Literal["http"]
68
+ asgi: ASGIVersions
69
+ http_version: str
70
+ method: str
71
+ scheme: str
72
+ path: str
73
+ raw_path: bytes
74
+ query_string: bytes
75
+ root_path: str
76
+ headers: Iterable[Tuple[bytes, bytes]]
77
+ client: Optional[Tuple[str, int]]
78
+ server: Optional[Tuple[str, Optional[int]]]
79
+ state: NotRequired[Dict[str, Any]]
80
+ extensions: Optional[Dict[str, Dict[object, object]]]
81
+
82
+
83
+ class WebSocketScope(TypedDict):
84
+ type: Literal["websocket"]
85
+ asgi: ASGIVersions
86
+ http_version: str
87
+ scheme: str
88
+ path: str
89
+ raw_path: bytes
90
+ query_string: bytes
91
+ root_path: str
92
+ headers: Iterable[Tuple[bytes, bytes]]
93
+ client: Optional[Tuple[str, int]]
94
+ server: Optional[Tuple[str, Optional[int]]]
95
+ subprotocols: Iterable[str]
96
+ state: NotRequired[Dict[str, Any]]
97
+ extensions: Optional[Dict[str, Dict[object, object]]]
98
+
99
+
100
+ class LifespanScope(TypedDict):
101
+ type: Literal["lifespan"]
102
+ asgi: ASGIVersions
103
+ state: NotRequired[Dict[str, Any]]
104
+
105
+
106
+ WWWScope = Union[HTTPScope, WebSocketScope]
107
+ Scope = Union[HTTPScope, WebSocketScope, LifespanScope]
108
+
109
+
110
+ class HTTPRequestEvent(TypedDict):
111
+ type: Literal["http.request"]
112
+ body: bytes
113
+ more_body: bool
114
+
115
+
116
+ class HTTPResponseDebugEvent(TypedDict):
117
+ type: Literal["http.response.debug"]
118
+ info: Dict[str, object]
119
+
120
+
121
+ class HTTPResponseStartEvent(TypedDict):
122
+ type: Literal["http.response.start"]
123
+ status: int
124
+ headers: Iterable[Tuple[bytes, bytes]]
125
+ trailers: bool
126
+
127
+
128
+ class HTTPResponseBodyEvent(TypedDict):
129
+ type: Literal["http.response.body"]
130
+ body: bytes
131
+ more_body: bool
132
+
133
+
134
+ class HTTPResponseTrailersEvent(TypedDict):
135
+ type: Literal["http.response.trailers"]
136
+ headers: Iterable[Tuple[bytes, bytes]]
137
+ more_trailers: bool
138
+
139
+
140
+ class HTTPResponsePathsendEvent(TypedDict):
141
+ type: Literal["http.response.pathsend"]
142
+ path: str
143
+
144
+
145
+ class HTTPServerPushEvent(TypedDict):
146
+ type: Literal["http.response.push"]
147
+ path: str
148
+ headers: Iterable[Tuple[bytes, bytes]]
149
+
150
+
151
+ class HTTPDisconnectEvent(TypedDict):
152
+ type: Literal["http.disconnect"]
153
+
154
+
155
+ class WebSocketConnectEvent(TypedDict):
156
+ type: Literal["websocket.connect"]
157
+
158
+
159
+ class WebSocketAcceptEvent(TypedDict):
160
+ type: Literal["websocket.accept"]
161
+ subprotocol: Optional[str]
162
+ headers: Iterable[Tuple[bytes, bytes]]
163
+
164
+
165
+ class WebSocketReceiveEvent(TypedDict):
166
+ type: Literal["websocket.receive"]
167
+ bytes: Optional[bytes]
168
+ text: Optional[str]
169
+
170
+
171
+ class WebSocketSendEvent(TypedDict):
172
+ type: Literal["websocket.send"]
173
+ bytes: Optional[bytes]
174
+ text: Optional[str]
175
+
176
+
177
+ class WebSocketResponseStartEvent(TypedDict):
178
+ type: Literal["websocket.http.response.start"]
179
+ status: int
180
+ headers: Iterable[Tuple[bytes, bytes]]
181
+
182
+
183
+ class WebSocketResponseBodyEvent(TypedDict):
184
+ type: Literal["websocket.http.response.body"]
185
+ body: bytes
186
+ more_body: bool
187
+
188
+
189
+ class WebSocketDisconnectEvent(TypedDict):
190
+ type: Literal["websocket.disconnect"]
191
+ code: int
192
+ reason: Optional[str]
193
+
194
+
195
+ class WebSocketCloseEvent(TypedDict):
196
+ type: Literal["websocket.close"]
197
+ code: int
198
+ reason: Optional[str]
199
+
200
+
201
+ class LifespanStartupEvent(TypedDict):
202
+ type: Literal["lifespan.startup"]
203
+
204
+
205
+ class LifespanShutdownEvent(TypedDict):
206
+ type: Literal["lifespan.shutdown"]
207
+
208
+
209
+ class LifespanStartupCompleteEvent(TypedDict):
210
+ type: Literal["lifespan.startup.complete"]
211
+
212
+
213
+ class LifespanStartupFailedEvent(TypedDict):
214
+ type: Literal["lifespan.startup.failed"]
215
+ message: str
216
+
217
+
218
+ class LifespanShutdownCompleteEvent(TypedDict):
219
+ type: Literal["lifespan.shutdown.complete"]
220
+
221
+
222
+ class LifespanShutdownFailedEvent(TypedDict):
223
+ type: Literal["lifespan.shutdown.failed"]
224
+ message: str
225
+
226
+
227
+ ASGIReceiveEvent = Union[
228
+ HTTPRequestEvent,
229
+ HTTPDisconnectEvent,
230
+ WebSocketConnectEvent,
231
+ WebSocketReceiveEvent,
232
+ WebSocketDisconnectEvent,
233
+ LifespanStartupEvent,
234
+ LifespanShutdownEvent,
235
+ ]
236
+
237
+
238
+ ASGISendEvent = Union[
239
+ HTTPResponseStartEvent,
240
+ HTTPResponseBodyEvent,
241
+ HTTPResponseTrailersEvent,
242
+ HTTPServerPushEvent,
243
+ HTTPDisconnectEvent,
244
+ WebSocketAcceptEvent,
245
+ WebSocketSendEvent,
246
+ WebSocketResponseStartEvent,
247
+ WebSocketResponseBodyEvent,
248
+ WebSocketCloseEvent,
249
+ LifespanStartupCompleteEvent,
250
+ LifespanStartupFailedEvent,
251
+ LifespanShutdownCompleteEvent,
252
+ LifespanShutdownFailedEvent,
253
+ ]
254
+
255
+
256
+ ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]]
257
+ ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]]
258
+
259
+
260
+ class ASGI2Protocol(Protocol):
261
+ def __init__(self, scope: Scope) -> None:
262
+ ...
263
+
264
+ async def __call__(
265
+ self, receive: ASGIReceiveCallable, send: ASGISendCallable
266
+ ) -> None:
267
+ ...
268
+
269
+
270
+ ASGI2Application = Type[ASGI2Protocol]
271
+ ASGI3Application = Callable[
272
+ [
273
+ Scope,
274
+ ASGIReceiveCallable,
275
+ ASGISendCallable,
276
+ ],
277
+ Awaitable[None],
278
+ ]
279
+ ASGIApplication = Union[ASGI2Application, ASGI3Application]
@@ -18,8 +18,6 @@ class Settings:
18
18
  os.getenv('SPACES_ZERO_GPU'))
19
19
  self.zero_device_api_url = (
20
20
  os.getenv('SPACES_ZERO_DEVICE_API_URL'))
21
- self.gradio_auto_wrap = boolean(
22
- os.getenv('SPACES_GRADIO_AUTO_WRAP'))
23
21
  self.zero_patch_torch_device = boolean(
24
22
  os.getenv('ZERO_GPU_PATCH_TORCH_DEVICE'))
25
23
  self.zero_gpu_v2 = boolean(
@@ -1,8 +1,10 @@
1
1
  """
2
2
  """
3
+
3
4
  import threading
4
5
  from typing import Any
5
6
  from typing import Callable
7
+ from uuid import uuid4
6
8
 
7
9
 
8
10
  reload_server_ports: set[int] = set()
@@ -14,6 +16,7 @@ def start_reload_server(
14
16
  stop_event: threading.Event,
15
17
  port: int = 7887,
16
18
  ):
19
+ from ..zero.context import GlobalContext
17
20
  from .server import ReloadServer
18
21
 
19
22
  reload_server = ReloadServer(
@@ -22,8 +25,9 @@ def start_reload_server(
22
25
  stop_event=stop_event,
23
26
  )
24
27
 
25
- reload_server_ports.add(port)
28
+ server_port_uuid = uuid4()
29
+ GlobalContext.server_ports[server_port_uuid] = port
26
30
  try:
27
31
  reload_server.run(port=port)
28
32
  finally:
29
- reload_server_ports.remove(port)
33
+ del GlobalContext.server_ports[server_port_uuid]
@@ -12,6 +12,11 @@ from typing_extensions import assert_type
12
12
  from typing_extensions import Never
13
13
  from uuid import uuid4
14
14
 
15
+ try:
16
+ import fastapi, uvicorn
17
+ except ModuleNotFoundError: # pragma: no cover
18
+ raise RuntimeError("spaces.reloading.server requires FastAPI and uvicorn")
19
+
15
20
  from fastapi import APIRouter
16
21
  from fastapi import FastAPI
17
22
  from fastapi import HTTPException
@@ -30,10 +30,8 @@ class SimpleQueue(_SimpleQueue[T]):
30
30
  raise # pragma: no cover
31
31
  # https://bugs.python.org/issue29187
32
32
  except Exception as e:
33
- message = str(e)
34
- if not "pickle" in message:
35
- raise # pragma: no cover
36
- raise PicklingError(message)
33
+ # Always assume a PicklingError
34
+ raise PicklingError from e
37
35
  def wlock_release(self):
38
36
  if (lock := getattr(self, '_wlock', None)) is None:
39
37
  return # pragma: no cover
@@ -49,17 +47,12 @@ def drop_params(fn: Callable[[], T]) -> Callable[..., T]:
49
47
  return drop
50
48
 
51
49
 
52
- def gradio_request_var():
53
- try:
54
- from gradio.context import LocalContext
55
- except ImportError: # pragma: no cover
56
- raise RuntimeError(GRADIO_VERSION_ERROR_MESSAGE)
57
- return LocalContext.request
58
-
59
-
60
50
  debug = partial(print, 'SPACES_ZERO_GPU_DEBUG')
61
51
 
62
52
 
63
53
  # Type-safe threads
64
54
  def create_thread(fn: Callable[P, Any], *args: P.args, **kwargs: P.kwargs) -> Thread:
65
55
  return Thread(target=fn, args=args, kwargs=kwargs)
56
+
57
+ def create_thread_daemon(fn: Callable[P, Any], *args: P.args, **kwargs: P.kwargs) -> Thread:
58
+ return Thread(target=fn, args=args, kwargs=kwargs, daemon=True)
@@ -0,0 +1,46 @@
1
+ """
2
+ """
3
+
4
+ from importlib import metadata
5
+
6
+ from packaging.version import Version
7
+
8
+ from ..config import Config
9
+ from .context import ZeroGPUError
10
+ from .context import ZeroGPUErrorResponse
11
+ from .context import ZeroGPUException
12
+ from .context import ZeroGPULog
13
+ from .middleware import ZeroGPUMiddleware
14
+ from .lifecycle import default_gpu_size
15
+ from .lifecycle import zerogpu_mode_enable
16
+ from .lifecycle import zerogpu_mode_enabled
17
+ from .lifecycle import zerogpu_startup
18
+
19
+
20
+ def _maybe_enable_gradio_compat():
21
+ try:
22
+ gradio_version = metadata.version('gradio')
23
+ except metadata.PackageNotFoundError: # pragma: no cover
24
+ pass
25
+ else:
26
+ if Version(gradio_version) < Version('7.0.0.dev0'):
27
+ from . import gradio
28
+ gradio.patch()
29
+
30
+
31
+ if Config.zero_gpu:
32
+ zerogpu_mode_enable()
33
+ _maybe_enable_gradio_compat()
34
+
35
+
36
+ __all__ = [
37
+ 'ZeroGPUError',
38
+ 'ZeroGPUErrorResponse',
39
+ 'ZeroGPUException',
40
+ 'ZeroGPULog',
41
+ 'ZeroGPUMiddleware',
42
+ 'default_gpu_size',
43
+ 'zerogpu_mode_enable',
44
+ 'zerogpu_mode_enabled',
45
+ 'zerogpu_startup',
46
+ ]