spaces 0.52.0.dev1__tar.gz → 0.52.0.dev2__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 (74) hide show
  1. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/PKG-INFO +1 -1
  2. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/pyproject.toml +1 -1
  3. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/__init__.py +2 -2
  4. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/client.py +4 -4
  5. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/context.py +10 -0
  6. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/gradio.py +39 -14
  7. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/middleware.py +2 -2
  8. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/wrappers.py +3 -3
  9. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/README.md +0 -0
  10. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/__init__.py +0 -0
  11. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/asgiref/__init__.py +0 -0
  12. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/asgiref/typing.py +0 -0
  13. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/codefind/LICENSE +0 -0
  14. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/codefind/__init__.py +0 -0
  15. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/codefind/registry.py +0 -0
  16. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/codefind/version.py +0 -0
  17. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/jurigged/LICENSE +0 -0
  18. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/jurigged/__init__.py +0 -0
  19. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/jurigged/codetools.py +0 -0
  20. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/jurigged/parse.py +0 -0
  21. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/jurigged/register.py +0 -0
  22. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/jurigged/utils.py +0 -0
  23. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/jurigged/version.py +0 -0
  24. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/LICENSE +0 -0
  25. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/__init__.py +0 -0
  26. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/abc.py +0 -0
  27. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/codegen.py +0 -0
  28. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/core.py +0 -0
  29. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/dependent.py +0 -0
  30. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/medley.py +0 -0
  31. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/mro.py +0 -0
  32. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/py.typed +0 -0
  33. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/recode.py +0 -0
  34. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/signatures.py +0 -0
  35. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/typemap.py +0 -0
  36. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/types.py +0 -0
  37. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/utils.py +0 -0
  38. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/ovld/version.py +0 -0
  39. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/sse_starlette/LICENSE +0 -0
  40. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/sse_starlette/__init__.py +0 -0
  41. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/sse_starlette/event.py +0 -0
  42. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/sse_starlette/py.typed +0 -0
  43. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/sse_starlette/sse.py +0 -0
  44. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/sseclient/LICENSE +0 -0
  45. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/_vendor/sseclient/__init__.py +0 -0
  46. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/config.py +0 -0
  47. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/reloading/__init__.py +0 -0
  48. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/reloading/client.py +0 -0
  49. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/reloading/server.py +0 -0
  50. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/reloading/types.py +0 -0
  51. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/reloading/types.ts +0 -0
  52. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/utils.py +0 -0
  53. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/__init__.py +0 -0
  54. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/api.py +0 -0
  55. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/config.py +0 -0
  56. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/configs.json +0 -0
  57. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/decorator.py +0 -0
  58. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/elf.py +0 -0
  59. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/lifecycle.py +0 -0
  60. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/mmap.py +0 -0
  61. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/__init__.py +0 -0
  62. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/aoti.py +0 -0
  63. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/bitsandbytes.py +0 -0
  64. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/bitsandbytes_legacy.py +0 -0
  65. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/cudart.py +0 -0
  66. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/packing.py +0 -0
  67. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/patching.py +0 -0
  68. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/patching_legacy.py +0 -0
  69. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/static.py +0 -0
  70. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/types.py +0 -0
  71. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/torch/utils.py +0 -0
  72. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/tqdm.py +0 -0
  73. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/types.py +0 -0
  74. {spaces-0.52.0.dev1 → spaces-0.52.0.dev2}/spaces/zero/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spaces
3
- Version: 0.52.0.dev1
3
+ Version: 0.52.0.dev2
4
4
  Summary: Utilities for Hugging Face Spaces
5
5
  Author: Charles Bensimon
6
6
  Author-email: Charles Bensimon <charles@huggingface.co>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "spaces"
3
- version = "0.52.0.dev1"
3
+ version = "0.52.0.dev2"
4
4
  description = "Utilities for Hugging Face Spaces"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.15"
@@ -19,8 +19,8 @@ if (gr := sys.modules.get('gradio')) is not None: # pragma: no cover
19
19
  from .zero.decorator import GPU
20
20
 
21
21
 
22
- def gradio_auto_wrap(*args, **kwargs): # pragma: no cover
23
- warnings.warn("gradio_auto_wrap has no effect and is deprecated")
22
+ def gradio_auto_wrap(task): # pragma: no cover
23
+ return task
24
24
 
25
25
  def disable_gradio_auto_wrap(*args, **kwargs): # pragma: no cover
26
26
  warnings.warn("gradio_auto_wrap has no effect and is deprecated")
@@ -18,7 +18,7 @@ from .api import GPUSize
18
18
  from .api import AuthLevel
19
19
  from .api import QuotaInfos
20
20
  from .api import ScheduleResponse
21
- from .context import ctx_var
21
+ from .context import get_context
22
22
  from .context import ZeroGPUContext
23
23
 
24
24
 
@@ -104,7 +104,7 @@ def schedule(
104
104
  _first_attempt: bool = True,
105
105
  ) -> ScheduleResponse:
106
106
 
107
- ctx = ctx_var.get()
107
+ ctx = get_context()
108
108
  token, payload = _get_token_and_payload(ctx.headers)
109
109
  if token is not None and (token_error := payload.get('error')):
110
110
  message = f"Falling back to IP-based quotas ({token_error})"
@@ -287,7 +287,7 @@ def release(
287
287
  allow_404: bool = False,
288
288
  ) -> None:
289
289
 
290
- ctx = ctx_var.get()
290
+ ctx = get_context()
291
291
  res = api_client().release(
292
292
  allow_token=allow_token,
293
293
  fail=fail,
@@ -327,7 +327,7 @@ def _get_token_and_payload(headers: dict[str, str]) -> tuple[str | None, dict[st
327
327
 
328
328
 
329
329
  def duration_warning():
330
- ctx_var.get().warning(
330
+ get_context().warning(
331
331
  title="ZeroGPU duration",
332
332
  message="GPU task is exceeding its requested duration and might be aborted",
333
333
  )
@@ -120,3 +120,13 @@ class ZeroGPUContext:
120
120
 
121
121
 
122
122
  ctx_var: ContextVar[ZeroGPUContext] = ContextVar('zerogpu_context', default=ZeroGPUContext())
123
+
124
+
125
+ _context_resolver: Callable[[], ZeroGPUContext | None] | None = None
126
+
127
+ def get_context() -> ZeroGPUContext:
128
+ if _context_resolver is not None:
129
+ ctx = _context_resolver()
130
+ if ctx is not None:
131
+ return ctx
132
+ return ctx_var.get()
@@ -5,7 +5,7 @@ import os
5
5
  from functools import wraps
6
6
  from typing import Any
7
7
  from typing import Literal
8
- from typing import Type
8
+ from typing import cast
9
9
 
10
10
  import gradio as gr
11
11
  from fastapi import FastAPI
@@ -18,8 +18,14 @@ from gradio.routes import App
18
18
 
19
19
  from ..utils import create_thread_daemon
20
20
  from ..utils import SimpleQueue
21
+ from . import context
22
+ from .context import ZeroGPUContext
23
+ from .context import ZeroGPUErrorResponse
24
+ from .context import ZeroGPULog
21
25
  from .lifecycle import zerogpu_mode_enabled
22
26
  from .lifecycle import zerogpu_startup
27
+ from .middleware import ASGIScope
28
+ from .middleware import get_server_port
23
29
  from .middleware import ZeroGPUMiddleware
24
30
 
25
31
 
@@ -84,24 +90,42 @@ def patch():
84
90
  case 'warning':
85
91
  return gr.Warning(message, **kwargs)
86
92
 
93
+ def exception_mapper(err: ZeroGPUErrorResponse, exc: Exception | None):
94
+ if isinstance(exc, gr.Error):
95
+ setattr(exc, 'print_exception', False)
96
+ return exc
97
+ detail = err['detail']
98
+ return error(
99
+ title=detail['title'],
100
+ message=detail['message'],
101
+ )
102
+
103
+ def log_emitter(log: ZeroGPULog):
104
+ return info(
105
+ title=log['title'],
106
+ message=log['message'],
107
+ level=log['level'],
108
+ )
109
+
110
+ def resolve_context():
111
+ if zerogpu_mode_enabled() and (request := LocalContext.request.get(None)) is not None:
112
+ scope = cast(ASGIScope | None, request.request.scope if request.request is not None else None)
113
+ return ZeroGPUContext(
114
+ exception_mapper=exception_mapper,
115
+ log_emitter=log_emitter,
116
+ worker_contextualizer=WorkerContextualizer,
117
+ disconnect_detector=disconnect_detector,
118
+ server_port=get_server_port(scope) if scope is not None else None,
119
+ headers={key.lower(): value for key, value in dict(getattr(request, 'headers', {})).items()},
120
+ )
121
+
87
122
  def setup_middleware(app: FastAPI, *, skip_zerogpu_startup: bool = False):
88
123
  mounted = any(middleware.cls is ZeroGPUMiddleware for middleware in app.user_middleware)
89
124
  if not mounted:
90
125
  app.add_middleware(
91
126
  ZeroGPUMiddleware,
92
- exception_mapper=lambda err, exc: (
93
- setattr(exc, 'print_exception', False) or exc
94
- if isinstance(exc, gr.Error)
95
- else error(
96
- title=err['detail']['title'],
97
- message=err['detail']['message'],
98
- )
99
- ),
100
- log_emitter=lambda log: info(
101
- title=log['title'],
102
- message=log['message'],
103
- level=log['level'],
104
- ),
127
+ exception_mapper=exception_mapper,
128
+ log_emitter=log_emitter,
105
129
  worker_contextualizer=WorkerContextualizer,
106
130
  disconnect_detector=disconnect_detector,
107
131
  skip_zerogpu_startup=skip_zerogpu_startup,
@@ -129,6 +153,7 @@ def patch():
129
153
  gr.mount_gradio_app = mount_gradio_app
130
154
  routes.mount_gradio_app = mount_gradio_app
131
155
  http_server.start_server = start_server
156
+ context._context_resolver = resolve_context
132
157
  _patch_queue()
133
158
 
134
159
 
@@ -87,7 +87,7 @@ class ZeroGPUMiddleware:
87
87
  worker_contextualizer=self.worker_contextualizer,
88
88
  disconnect_detector=self.disconnect_detector,
89
89
  connection_state=connection_state,
90
- server_port=_server_port(asgi_scope),
90
+ server_port=get_server_port(asgi_scope),
91
91
  headers=_decode_headers(asgi_scope.get('headers', [])),
92
92
  ))
93
93
 
@@ -97,7 +97,7 @@ class ZeroGPUMiddleware:
97
97
  ctx_var.reset(token)
98
98
 
99
99
 
100
- def _server_port(scope: ASGIScope):
100
+ def get_server_port(scope: ASGIScope):
101
101
  match scope.get('server'):
102
102
  case (_, int() as port):
103
103
  return port
@@ -34,7 +34,7 @@ from .api import AllowToken
34
34
  from .api import GPUSize
35
35
  from .api import NvidiaIndex
36
36
  from .api import NvidiaUUID
37
- from .context import ctx_var
37
+ from .context import get_context
38
38
  from .tqdm import remove_tqdm_multiprocessing_lock
39
39
  from .tqdm import tqdm
40
40
  from .utils import apply_cleanups
@@ -170,7 +170,7 @@ def regular_function_wrapper(
170
170
  if forked:
171
171
  return task(*args, **kwargs)
172
172
 
173
- ctx = ctx_var.get()
173
+ ctx = get_context()
174
174
  duration_ = static_duration(duration, *args, **kwargs)
175
175
  duration_ = process_duration(duration_)
176
176
  schedule_response = client.schedule(task_id=task_id, duration=duration_, gpu_size=gpu_size)
@@ -297,7 +297,7 @@ def generator_function_wrapper(
297
297
  yield from task(*args, **kwargs)
298
298
  return
299
299
 
300
- ctx = ctx_var.get()
300
+ ctx = get_context()
301
301
  duration_ = static_duration(duration, *args, **kwargs)
302
302
  duration_ = process_duration(duration_)
303
303
  schedule_response = client.schedule(task_id=task_id, duration=duration_, gpu_size=gpu_size)
File without changes