anyscale 0.26.51__py3-none-any.whl → 0.26.52__py3-none-any.whl
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.
- anyscale/_private/anyscale_client/README.md +1 -1
- anyscale/_private/anyscale_client/anyscale_client.py +178 -46
- anyscale/_private/anyscale_client/common.py +61 -2
- anyscale/_private/anyscale_client/fake_anyscale_client.py +145 -8
- anyscale/_private/docgen/__main__.py +34 -23
- anyscale/_private/docgen/generator.py +15 -18
- anyscale/_private/docgen/models.md +4 -2
- anyscale/_private/workload/workload_sdk.py +103 -8
- anyscale/client/README.md +3 -0
- anyscale/client/openapi_client/__init__.py +1 -0
- anyscale/client/openapi_client/api/default_api.py +249 -0
- anyscale/client/openapi_client/models/__init__.py +1 -0
- anyscale/client/openapi_client/models/baseimagesenum.py +83 -1
- anyscale/client/openapi_client/models/cloud_resource.py +59 -3
- anyscale/client/openapi_client/models/cloud_resource_gcp.py +59 -3
- anyscale/client/openapi_client/models/clouddeployment_response.py +121 -0
- anyscale/client/openapi_client/models/create_cloud_resource.py +59 -3
- anyscale/client/openapi_client/models/create_cloud_resource_gcp.py +59 -3
- anyscale/client/openapi_client/models/object_storage.py +2 -2
- anyscale/client/openapi_client/models/ray_runtime_env_config.py +57 -1
- anyscale/client/openapi_client/models/supportedbaseimagesenum.py +80 -1
- anyscale/cloud/models.py +1 -1
- anyscale/commands/cloud_commands.py +73 -70
- anyscale/commands/command_examples.py +28 -40
- anyscale/commands/project_commands.py +377 -106
- anyscale/controllers/cloud_controller.py +81 -86
- anyscale/job/_private/job_sdk.py +38 -20
- anyscale/project/__init__.py +101 -1
- anyscale/project/_private/project_sdk.py +90 -2
- anyscale/project/commands.py +188 -1
- anyscale/project/models.py +198 -2
- anyscale/sdk/anyscale_client/models/baseimagesenum.py +83 -1
- anyscale/sdk/anyscale_client/models/ray_runtime_env_config.py +57 -1
- anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +80 -1
- anyscale/service/_private/service_sdk.py +2 -1
- anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
- anyscale/util.py +3 -0
- anyscale/utils/runtime_env.py +3 -1
- anyscale/version.py +1 -1
- {anyscale-0.26.51.dist-info → anyscale-0.26.52.dist-info}/METADATA +1 -1
- {anyscale-0.26.51.dist-info → anyscale-0.26.52.dist-info}/RECORD +46 -45
- {anyscale-0.26.51.dist-info → anyscale-0.26.52.dist-info}/WHEEL +0 -0
- {anyscale-0.26.51.dist-info → anyscale-0.26.52.dist-info}/entry_points.txt +0 -0
- {anyscale-0.26.51.dist-info → anyscale-0.26.52.dist-info}/licenses/LICENSE +0 -0
- {anyscale-0.26.51.dist-info → anyscale-0.26.52.dist-info}/licenses/NOTICE +0 -0
- {anyscale-0.26.51.dist-info → anyscale-0.26.52.dist-info}/top_level.txt +0 -0
anyscale/project/commands.py
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
from typing import List, Optional
|
2
2
|
|
3
|
+
from anyscale._private.models.model_base import ResultIterator
|
3
4
|
from anyscale._private.sdk import sdk_command
|
4
5
|
from anyscale.project._private.project_sdk import PrivateProjectSDK
|
5
|
-
from anyscale.project.models import
|
6
|
+
from anyscale.project.models import (
|
7
|
+
CreateProjectCollaborator,
|
8
|
+
Project,
|
9
|
+
ProjectSortField,
|
10
|
+
ProjectSortOrder,
|
11
|
+
)
|
6
12
|
|
7
13
|
|
8
14
|
_PROJECT_SDK_SINGLETON_KEY = "project_sdk"
|
@@ -54,3 +60,184 @@ def add_collaborators(
|
|
54
60
|
"""Batch add collaborators to a project.
|
55
61
|
"""
|
56
62
|
return _private_sdk.add_collaborators(cloud, project, collaborators) # type: ignore
|
63
|
+
|
64
|
+
|
65
|
+
_GET_PROJECT_EXAMPLE = """
|
66
|
+
import anyscale
|
67
|
+
from anyscale.project.models import Project
|
68
|
+
|
69
|
+
project: Project = anyscale.project.get(project_id="my-project-id")
|
70
|
+
"""
|
71
|
+
|
72
|
+
_GET_PROJECT_DOCSTRINGS = {
|
73
|
+
"project_id": "The ID of the project to get details of.",
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
@sdk_command(
|
78
|
+
_PROJECT_SDK_SINGLETON_KEY,
|
79
|
+
PrivateProjectSDK,
|
80
|
+
doc_py_example=_GET_PROJECT_EXAMPLE,
|
81
|
+
arg_docstrings=_GET_PROJECT_DOCSTRINGS,
|
82
|
+
)
|
83
|
+
def get(
|
84
|
+
project_id: str, *, _private_sdk: Optional[PrivateProjectSDK] = None
|
85
|
+
) -> Project:
|
86
|
+
"""Get details of a project.
|
87
|
+
"""
|
88
|
+
return _private_sdk.get(project_id) # type: ignore
|
89
|
+
|
90
|
+
|
91
|
+
_LIST_PROJECTS_EXAMPLE = """
|
92
|
+
from typing import Iterator
|
93
|
+
|
94
|
+
import anyscale
|
95
|
+
from anyscale.project.models import Project, ProjectSortField, ProjectSortOrder
|
96
|
+
|
97
|
+
projects: Iterator[Project] = anyscale.project.list(
|
98
|
+
name_contains="my-project",
|
99
|
+
creator_id="my-user-id",
|
100
|
+
parent_cloud_id="my-cloud-id",
|
101
|
+
include_defaults=True,
|
102
|
+
max_items=20,
|
103
|
+
page_size=10,
|
104
|
+
sort_field=ProjectSortField.NAME,
|
105
|
+
sort_order=ProjectSortOrder.ASC,
|
106
|
+
)
|
107
|
+
for project in projects:
|
108
|
+
print(project.name)
|
109
|
+
"""
|
110
|
+
|
111
|
+
_LIST_PROJECTS_DOCSTRINGS = {
|
112
|
+
"name_contains": "A string to filter projects by name.",
|
113
|
+
"creator_id": "The ID of a creator to filter projects.",
|
114
|
+
"parent_cloud_id": "The ID of a parent cloud to filter projects.",
|
115
|
+
"include_defaults": "Whether to include default projects.",
|
116
|
+
"max_items": "The maximum number of projects to return.",
|
117
|
+
"page_size": "The number of projects to return per page.",
|
118
|
+
"sort_field": "The field to sort projects by.",
|
119
|
+
"sort_order": "The order to sort projects by.",
|
120
|
+
}
|
121
|
+
|
122
|
+
|
123
|
+
@sdk_command(
|
124
|
+
_PROJECT_SDK_SINGLETON_KEY,
|
125
|
+
PrivateProjectSDK,
|
126
|
+
doc_py_example=_LIST_PROJECTS_EXAMPLE,
|
127
|
+
arg_docstrings=_LIST_PROJECTS_DOCSTRINGS,
|
128
|
+
)
|
129
|
+
def list( # noqa: A001
|
130
|
+
*,
|
131
|
+
name_contains: Optional[str] = None,
|
132
|
+
creator_id: Optional[str] = None,
|
133
|
+
parent_cloud_id: Optional[str] = None,
|
134
|
+
include_defaults: bool = True,
|
135
|
+
max_items: Optional[int] = None,
|
136
|
+
page_size: Optional[int] = None,
|
137
|
+
sort_field: Optional[ProjectSortField] = None,
|
138
|
+
sort_order: Optional[ProjectSortOrder] = None,
|
139
|
+
_private_sdk: Optional[PrivateProjectSDK] = None
|
140
|
+
) -> ResultIterator[Project]:
|
141
|
+
"""List projects.
|
142
|
+
"""
|
143
|
+
return _private_sdk.list( # type: ignore
|
144
|
+
name_contains=name_contains,
|
145
|
+
creator_id=creator_id,
|
146
|
+
parent_cloud_id=parent_cloud_id,
|
147
|
+
include_defaults=include_defaults,
|
148
|
+
max_items=max_items,
|
149
|
+
page_size=page_size,
|
150
|
+
sort_field=sort_field,
|
151
|
+
sort_order=sort_order,
|
152
|
+
)
|
153
|
+
|
154
|
+
|
155
|
+
_CREATE_PROJECT_EXAMPLE = """
|
156
|
+
import anyscale
|
157
|
+
|
158
|
+
project_id: str = anyscale.project.create(
|
159
|
+
name="my-project",
|
160
|
+
parent_cloud_id="my-cloud-id",
|
161
|
+
description="my-project-description",
|
162
|
+
)
|
163
|
+
"""
|
164
|
+
|
165
|
+
_CREATE_PROJECT_DOCSTRINGS = {
|
166
|
+
"name": "The name of the project.",
|
167
|
+
"parent_cloud_id": "The parent cloud that the project belongs to.",
|
168
|
+
"description": "The description of the project.",
|
169
|
+
"initial_cluster_config": "A YAML string containing the initial cluster config for the project.",
|
170
|
+
}
|
171
|
+
|
172
|
+
|
173
|
+
@sdk_command(
|
174
|
+
_PROJECT_SDK_SINGLETON_KEY,
|
175
|
+
PrivateProjectSDK,
|
176
|
+
doc_py_example=_CREATE_PROJECT_EXAMPLE,
|
177
|
+
arg_docstrings=_CREATE_PROJECT_DOCSTRINGS,
|
178
|
+
)
|
179
|
+
def create(
|
180
|
+
name: str,
|
181
|
+
parent_cloud_id: str,
|
182
|
+
*,
|
183
|
+
description: Optional[str] = None,
|
184
|
+
initial_cluster_config: Optional[str] = None,
|
185
|
+
_private_sdk: Optional[PrivateProjectSDK] = None
|
186
|
+
) -> str:
|
187
|
+
"""Create a project.
|
188
|
+
"""
|
189
|
+
return _private_sdk.create( # type: ignore
|
190
|
+
name,
|
191
|
+
description or "",
|
192
|
+
parent_cloud_id,
|
193
|
+
initial_cluster_config=initial_cluster_config,
|
194
|
+
)
|
195
|
+
|
196
|
+
|
197
|
+
_DELETE_PROJECT_EXAMPLE = """
|
198
|
+
import anyscale
|
199
|
+
|
200
|
+
anyscale.project.delete(project_id="my-project-id")
|
201
|
+
"""
|
202
|
+
|
203
|
+
_DELETE_PROJECT_DOCSTRINGS = {
|
204
|
+
"project_id": "The ID of the project to delete.",
|
205
|
+
}
|
206
|
+
|
207
|
+
|
208
|
+
@sdk_command(
|
209
|
+
_PROJECT_SDK_SINGLETON_KEY,
|
210
|
+
PrivateProjectSDK,
|
211
|
+
doc_py_example=_DELETE_PROJECT_EXAMPLE,
|
212
|
+
arg_docstrings=_DELETE_PROJECT_DOCSTRINGS,
|
213
|
+
)
|
214
|
+
def delete(project_id: str, *, _private_sdk: Optional[PrivateProjectSDK] = None):
|
215
|
+
"""Delete a project.
|
216
|
+
"""
|
217
|
+
_private_sdk.delete(project_id) # type: ignore
|
218
|
+
|
219
|
+
|
220
|
+
_GET_DEFAULT_PROJECT_EXAMPLE = """
|
221
|
+
import anyscale
|
222
|
+
from anyscale.project.models import Project
|
223
|
+
|
224
|
+
project: Project = anyscale.project.get_default(parent_cloud_id="my-cloud-id")
|
225
|
+
"""
|
226
|
+
|
227
|
+
_GET_DEFAULT_PROJECT_DOCSTRINGS = {
|
228
|
+
"parent_cloud_id": "The ID of the parent cloud to get the default project for.",
|
229
|
+
}
|
230
|
+
|
231
|
+
|
232
|
+
@sdk_command(
|
233
|
+
_PROJECT_SDK_SINGLETON_KEY,
|
234
|
+
PrivateProjectSDK,
|
235
|
+
doc_py_example=_GET_DEFAULT_PROJECT_EXAMPLE,
|
236
|
+
arg_docstrings=_GET_DEFAULT_PROJECT_DOCSTRINGS,
|
237
|
+
)
|
238
|
+
def get_default(
|
239
|
+
parent_cloud_id: str, *, _private_sdk: Optional[PrivateProjectSDK] = None
|
240
|
+
) -> Project:
|
241
|
+
"""Get the default project for a cloud.
|
242
|
+
"""
|
243
|
+
return _private_sdk.get_default(parent_cloud_id) # type: ignore
|
anyscale/project/models.py
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
|
2
|
-
from
|
1
|
+
import contextlib
|
2
|
+
from dataclasses import dataclass, field, fields
|
3
|
+
from datetime import datetime
|
4
|
+
import json
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
3
6
|
|
4
7
|
from anyscale._private.models import ModelBase, ModelEnum
|
5
8
|
|
@@ -89,3 +92,196 @@ create_project_collaborators = CreateProjectCollaborators(
|
|
89
92
|
def _validate_collaborators(self, collaborators: List[Dict[str, Any]]):
|
90
93
|
if not isinstance(collaborators, list):
|
91
94
|
raise TypeError("Collaborators must be a list.")
|
95
|
+
|
96
|
+
|
97
|
+
@dataclass(frozen=True)
|
98
|
+
class ProjectMinimal(ModelBase):
|
99
|
+
"""Minimal Project object."""
|
100
|
+
|
101
|
+
id: str = field(metadata={"docstring": "ID of the project."},)
|
102
|
+
|
103
|
+
def _validate_id(self, id: str): # noqa: A002
|
104
|
+
if not isinstance(id, str):
|
105
|
+
raise TypeError("'id' must be a string.")
|
106
|
+
|
107
|
+
name: str = field(metadata={"docstring": "Name of the project."},)
|
108
|
+
|
109
|
+
def _validate_name(self, name: str):
|
110
|
+
if not isinstance(name, str):
|
111
|
+
raise TypeError("'name' must be a string.")
|
112
|
+
|
113
|
+
description: str = field(metadata={"docstring": "Description of the project."},)
|
114
|
+
|
115
|
+
def _validate_description(self, description: str):
|
116
|
+
if not isinstance(description, str):
|
117
|
+
raise TypeError("'description' must be a string.")
|
118
|
+
|
119
|
+
created_at: str = field(
|
120
|
+
metadata={"docstring": "Datetime of the project creation."},
|
121
|
+
)
|
122
|
+
|
123
|
+
def _validate_created_at(self, created_at: str):
|
124
|
+
if not isinstance(created_at, str):
|
125
|
+
raise TypeError("'created_at' must be a string.")
|
126
|
+
|
127
|
+
creator_id: Optional[str] = field(
|
128
|
+
default=None, metadata={"docstring": "ID of the creator of the project."},
|
129
|
+
)
|
130
|
+
|
131
|
+
def _validate_creator_id(self, creator_id: Optional[str]):
|
132
|
+
if creator_id is not None and not isinstance(creator_id, str):
|
133
|
+
raise TypeError("'creator_id' must be a string.")
|
134
|
+
|
135
|
+
parent_cloud_id: Optional[str] = field(
|
136
|
+
default=None, metadata={"docstring": "ID of the parent cloud."},
|
137
|
+
)
|
138
|
+
|
139
|
+
def _validate_parent_cloud_id(self, parent_cloud_id: Optional[str]):
|
140
|
+
if parent_cloud_id is not None and not isinstance(parent_cloud_id, str):
|
141
|
+
raise TypeError("'parent_cloud_id' must be a string.")
|
142
|
+
|
143
|
+
@classmethod
|
144
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ProjectMinimal":
|
145
|
+
# remove any fields that are not in the dataclass
|
146
|
+
valid_fields = {field_.name for field_ in fields(cls)}
|
147
|
+
filtered_data = {k: v for k, v in data.items() if k in valid_fields}
|
148
|
+
return cls(**filtered_data)
|
149
|
+
|
150
|
+
|
151
|
+
@dataclass(frozen=True)
|
152
|
+
class Project(ProjectMinimal):
|
153
|
+
"""Project object.
|
154
|
+
"""
|
155
|
+
|
156
|
+
__doc_py_example__ = """\
|
157
|
+
import anyscale
|
158
|
+
from anyscale.project.models import Project
|
159
|
+
|
160
|
+
project: Project = anyscale.project.get(project_id="my-project-id")
|
161
|
+
"""
|
162
|
+
|
163
|
+
is_owner: bool = field(
|
164
|
+
default=False,
|
165
|
+
metadata={"docstring": "Whether the user is the owner of the project."},
|
166
|
+
)
|
167
|
+
|
168
|
+
def _validate_is_owner(self, is_owner: bool):
|
169
|
+
if not isinstance(is_owner, bool):
|
170
|
+
raise TypeError("'is_owner' must be a boolean.")
|
171
|
+
|
172
|
+
is_read_only: bool = field(
|
173
|
+
default=False,
|
174
|
+
metadata={"docstring": "Whether the user has read-only access to the project."},
|
175
|
+
)
|
176
|
+
|
177
|
+
def _validate_is_read_only(self, is_read_only: bool):
|
178
|
+
if not isinstance(is_read_only, bool):
|
179
|
+
raise TypeError("'is_read_only' must be a boolean.")
|
180
|
+
|
181
|
+
directory_name: str = field(
|
182
|
+
default="",
|
183
|
+
metadata={
|
184
|
+
"docstring": "Directory name of project to be used as working directory of clusters."
|
185
|
+
},
|
186
|
+
)
|
187
|
+
|
188
|
+
def _validate_directory_name(self, directory_name: str):
|
189
|
+
if not isinstance(directory_name, str):
|
190
|
+
raise TypeError("'directory_name' must be a string.")
|
191
|
+
|
192
|
+
is_default: bool = field(
|
193
|
+
default=False,
|
194
|
+
metadata={
|
195
|
+
"docstring": "Whether the project is the default project for the organization."
|
196
|
+
},
|
197
|
+
)
|
198
|
+
|
199
|
+
def _validate_is_default(self, is_default: bool):
|
200
|
+
if not isinstance(is_default, bool):
|
201
|
+
raise TypeError("'is_default' must be a boolean.")
|
202
|
+
|
203
|
+
initial_cluster_config: Optional[Union[str, Dict[str, Any]]] = field(
|
204
|
+
default=None,
|
205
|
+
metadata={"docstring": "Initial cluster config associated with the project."},
|
206
|
+
)
|
207
|
+
|
208
|
+
def _validate_initial_cluster_config(
|
209
|
+
self, initial_cluster_config: Union[str, Dict[str, Any], None]
|
210
|
+
):
|
211
|
+
if initial_cluster_config is not None and not isinstance(
|
212
|
+
initial_cluster_config, (str, dict)
|
213
|
+
):
|
214
|
+
raise TypeError("'initial_cluster_config' must be a string or dictionary.")
|
215
|
+
|
216
|
+
last_used_cloud_id: Optional[str] = field(
|
217
|
+
default=None,
|
218
|
+
metadata={
|
219
|
+
"docstring": "ID of the last cloud used in this project, or by the user if this is a new project."
|
220
|
+
},
|
221
|
+
)
|
222
|
+
|
223
|
+
def _validate_last_used_cloud_id(self, last_used_cloud_id: Optional[str]):
|
224
|
+
if last_used_cloud_id is not None and not isinstance(last_used_cloud_id, str):
|
225
|
+
raise TypeError("'last_used_cloud_id' must be a string.")
|
226
|
+
|
227
|
+
owners: List[str] = field(
|
228
|
+
default_factory=list,
|
229
|
+
metadata={
|
230
|
+
"docstring": "List of IDs of users who have owner access to the project."
|
231
|
+
},
|
232
|
+
)
|
233
|
+
|
234
|
+
def _validate_owners(self, owners: List[str]):
|
235
|
+
if not isinstance(owners, list):
|
236
|
+
raise TypeError("'owners' must be a list.")
|
237
|
+
for owner in owners:
|
238
|
+
if not isinstance(owner, str):
|
239
|
+
raise TypeError(f"'{owner}' must be a string.")
|
240
|
+
|
241
|
+
@classmethod
|
242
|
+
def from_dict(cls, d: Dict[str, Any]) -> "Project":
|
243
|
+
data = d.copy()
|
244
|
+
# convert datetime fields to string
|
245
|
+
for field_ in fields(cls):
|
246
|
+
if field_.name in data and isinstance(data[field_.name], datetime):
|
247
|
+
data[field_.name] = data[field_.name].strftime("%Y-%m-%d %H:%M:%S")
|
248
|
+
|
249
|
+
# convert initial_cluster_config JSON string to dict
|
250
|
+
if "initial_cluster_config" in data and isinstance(
|
251
|
+
data["initial_cluster_config"], str
|
252
|
+
):
|
253
|
+
with contextlib.suppress(json.JSONDecodeError):
|
254
|
+
data["initial_cluster_config"] = json.loads(
|
255
|
+
data["initial_cluster_config"]
|
256
|
+
)
|
257
|
+
|
258
|
+
# convert owners list of dicts to list of string IDs
|
259
|
+
if "owners" in data and isinstance(data["owners"], list):
|
260
|
+
data["owners"] = [owner.get("id") for owner in data["owners"]]
|
261
|
+
|
262
|
+
# remove any fields that are not in the dataclass
|
263
|
+
valid_fields = {field_.name for field_ in fields(cls)}
|
264
|
+
filtered_data = {k: v for k, v in data.items() if k in valid_fields}
|
265
|
+
return cls(**filtered_data)
|
266
|
+
|
267
|
+
|
268
|
+
class ProjectSortField(ModelEnum):
|
269
|
+
"""Field to sort projects by."""
|
270
|
+
|
271
|
+
NAME = "NAME"
|
272
|
+
|
273
|
+
__docstrings__ = {
|
274
|
+
NAME: "Sort by project name.",
|
275
|
+
}
|
276
|
+
|
277
|
+
|
278
|
+
class ProjectSortOrder(ModelEnum):
|
279
|
+
"""Direction of sorting."""
|
280
|
+
|
281
|
+
ASC = "ASC"
|
282
|
+
DESC = "DESC"
|
283
|
+
|
284
|
+
__docstrings__ = {
|
285
|
+
ASC: "Sort in ascending order.",
|
286
|
+
DESC: "Sort in descending order.",
|
287
|
+
}
|