cortexgrid 0.3.17__tar.gz → 0.3.18__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 (31) hide show
  1. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/PKG-INFO +1 -1
  2. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/serve.py +48 -4
  3. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/pyproject.toml +1 -1
  4. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/.gitignore +0 -0
  5. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/LICENSE +0 -0
  6. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/__init__.py +0 -0
  7. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_bundle.py +0 -0
  8. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_model_scheduler.py +0 -0
  9. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_ray_job_driver.py +0 -0
  10. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_serve_entry.py +0 -0
  11. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/checkpoint.py +0 -0
  12. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/experiment.py +0 -0
  13. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/infra.py +0 -0
  14. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/jobs.py +0 -0
  15. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/mlflow_util.py +0 -0
  16. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/__init__.py +0 -0
  17. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/application_spec.py +0 -0
  18. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/deployment_key.py +0 -0
  19. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/deployment_records.py +0 -0
  20. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/lifecycle.py +0 -0
  21. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/placement.py +0 -0
  22. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/registry_tags.py +0 -0
  23. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/serve_bundle.py +0 -0
  24. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/status.py +0 -0
  25. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_storage.py +0 -0
  26. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/py.typed +0 -0
  27. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/ray_util.py +0 -0
  28. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/s3_util.py +0 -0
  29. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/secrets.py +0 -0
  30. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/state.py +0 -0
  31. {cortexgrid-0.3.17 → cortexgrid-0.3.18}/docs/cortexgrid/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cortexgrid
3
- Version: 0.3.17
3
+ Version: 0.3.18
4
4
  Summary: Connect your ML code to the RoboLab compute cluster — Ray, MLflow, and S3
5
5
  Project-URL: Homepage, https://github.com/robodatalab/cortexgrid
6
6
  Project-URL: Repository, https://github.com/robodatalab/cortexgrid
@@ -24,11 +24,13 @@ locatable everywhere else (the laptop, Ray jobs, tests).
24
24
  from __future__ import annotations
25
25
 
26
26
  import inspect
27
+ from collections.abc import AsyncIterator
27
28
  from dataclasses import dataclass
28
- from typing import Any, Callable, TypeVar, get_type_hints
29
+ from typing import Any, Callable, TypeVar, get_args, get_type_hints
29
30
 
30
31
  import httpx
31
32
  from fastapi import FastAPI
33
+ from fastapi.responses import StreamingResponse
32
34
  from pydantic import TypeAdapter
33
35
 
34
36
  from cortexgrid.model_serving.lifecycle import Deployment, DeploymentClient
@@ -88,7 +90,12 @@ class _EndpointMarshalling:
88
90
  parameters_in_order = list(parameter_values)
89
91
  signature_without_self = signature.replace(parameters=parameters_in_order[1:])
90
92
  hints = get_type_hints(method)
91
- answer_hint = hints.pop("return")
93
+ returned_hint = hints.pop("return")
94
+ if inspect.isasyncgenfunction(method):
95
+ streamed_hints = get_args(returned_hint)
96
+ answer_hint = streamed_hints[0]
97
+ else:
98
+ answer_hint = returned_hint
92
99
  answer = TypeAdapter(answer_hint)
93
100
  parameters = {name: TypeAdapter(hint) for name, hint in hints.items()}
94
101
  return cls(signature_without_self, parameters, answer)
@@ -113,11 +120,27 @@ class _EndpointMarshalling:
113
120
  def answer_from_json(self, answered: Any) -> Any:
114
121
  return self.answer.validate_python(answered)
115
122
 
123
+ def answer_to_json_line(self, answer: Any) -> bytes:
124
+ answered = self.answer.dump_json(answer)
125
+ return answered + b"\n"
126
+
127
+ def answer_from_json_line(self, line: str) -> Any:
128
+ return self.answer.validate_json(line)
129
+
116
130
 
117
131
  def _route_of(
118
132
  method: Callable[..., Any], marshalling: _EndpointMarshalling
119
133
  ) -> Callable[..., Any]:
120
- if inspect.iscoroutinefunction(method):
134
+ if inspect.isasyncgenfunction(method):
135
+
136
+ async def route(self: Any, body: dict[str, Any]) -> Any:
137
+ arguments = marshalling.arguments_from_json(body)
138
+ answers = method(self, **arguments)
139
+ lines = _json_lines_of(answers, marshalling)
140
+ streamed = StreamingResponse(lines, media_type="application/x-ndjson")
141
+ return streamed
142
+
143
+ elif inspect.iscoroutinefunction(method):
121
144
 
122
145
  async def route(self: Any, body: dict[str, Any]) -> Any:
123
146
  arguments = marshalling.arguments_from_json(body)
@@ -138,10 +161,31 @@ def _route_of(
138
161
  return route
139
162
 
140
163
 
164
+ async def _json_lines_of(
165
+ answers: AsyncIterator[Any], marshalling: _EndpointMarshalling
166
+ ) -> AsyncIterator[bytes]:
167
+ async for answer in answers:
168
+ line = marshalling.answer_to_json_line(answer)
169
+ yield line
170
+
171
+
141
172
  def _call_of(
142
173
  name: str, method: Callable[..., Any], marshalling: _EndpointMarshalling
143
174
  ) -> Callable[..., Any]:
144
- if inspect.iscoroutinefunction(method):
175
+ if inspect.isasyncgenfunction(method):
176
+
177
+ async def call(self: _EndpointsClient, *args: Any, **kwargs: Any) -> Any:
178
+ body = marshalling.arguments_to_json(*args, **kwargs)
179
+ async with httpx.AsyncClient(timeout=None) as client:
180
+ async with client.stream(
181
+ "POST", f"{self.url}/{name}", json=body
182
+ ) as response:
183
+ response.raise_for_status()
184
+ async for line in response.aiter_lines():
185
+ answer = marshalling.answer_from_json_line(line)
186
+ yield answer
187
+
188
+ elif inspect.iscoroutinefunction(method):
145
189
 
146
190
  async def call(self: _EndpointsClient, *args: Any, **kwargs: Any) -> Any:
147
191
  body = marshalling.arguments_to_json(*args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cortexgrid"
3
- version = "0.3.17"
3
+ version = "0.3.18"
4
4
  description = "Connect your ML code to the RoboLab compute cluster — Ray, MLflow, and S3"
5
5
  readme = "docs/cortexgrid/README.md"
6
6
  license = "Apache-2.0"
File without changes
File without changes