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.
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/PKG-INFO +1 -1
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/serve.py +48 -4
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/pyproject.toml +1 -1
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/.gitignore +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/LICENSE +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/__init__.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_bundle.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_model_scheduler.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_ray_job_driver.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/_serve_entry.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/checkpoint.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/experiment.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/infra.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/jobs.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/mlflow_util.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/__init__.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/application_spec.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/deployment_key.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/deployment_records.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/lifecycle.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/placement.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/registry_tags.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/serve_bundle.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_serving/status.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/model_storage.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/py.typed +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/ray_util.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/s3_util.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/secrets.py +0 -0
- {cortexgrid-0.3.17 → cortexgrid-0.3.18}/cortexgrid/state.py +0 -0
- {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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|