anyscale 0.26.21__py3-none-any.whl → 0.26.23__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.
Files changed (32) hide show
  1. anyscale/_private/anyscale_client/anyscale_client.py +103 -43
  2. anyscale/_private/anyscale_client/common.py +38 -8
  3. anyscale/_private/anyscale_client/fake_anyscale_client.py +98 -27
  4. anyscale/_private/docgen/models.md +2 -2
  5. anyscale/_private/models/model_base.py +95 -0
  6. anyscale/_private/workload/workload_sdk.py +3 -1
  7. anyscale/aggregated_instance_usage/models.py +4 -4
  8. anyscale/client/README.md +1 -0
  9. anyscale/client/openapi_client/api/default_api.py +122 -1
  10. anyscale/client/openapi_client/models/baseimagesenum.py +68 -1
  11. anyscale/client/openapi_client/models/supportedbaseimagesenum.py +68 -1
  12. anyscale/commands/command_examples.py +4 -0
  13. anyscale/commands/list_util.py +107 -0
  14. anyscale/commands/service_commands.py +267 -31
  15. anyscale/commands/util.py +5 -4
  16. anyscale/controllers/service_controller.py +7 -86
  17. anyscale/sdk/anyscale_client/models/baseimagesenum.py +68 -1
  18. anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +68 -1
  19. anyscale/service/__init__.py +53 -3
  20. anyscale/service/_private/service_sdk.py +177 -41
  21. anyscale/service/commands.py +78 -1
  22. anyscale/service/models.py +65 -0
  23. anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
  24. anyscale/util.py +35 -1
  25. anyscale/version.py +1 -1
  26. {anyscale-0.26.21.dist-info → anyscale-0.26.23.dist-info}/METADATA +1 -1
  27. {anyscale-0.26.21.dist-info → anyscale-0.26.23.dist-info}/RECORD +32 -31
  28. {anyscale-0.26.21.dist-info → anyscale-0.26.23.dist-info}/LICENSE +0 -0
  29. {anyscale-0.26.21.dist-info → anyscale-0.26.23.dist-info}/NOTICE +0 -0
  30. {anyscale-0.26.21.dist-info → anyscale-0.26.23.dist-info}/WHEEL +0 -0
  31. {anyscale-0.26.21.dist-info → anyscale-0.26.23.dist-info}/entry_points.txt +0 -0
  32. {anyscale-0.26.21.dist-info → anyscale-0.26.23.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,13 @@
1
+ import asyncio
2
+ from collections import deque
1
3
  from dataclasses import asdict, fields
2
4
  from enum import Enum, EnumMeta
3
5
  import inspect
4
6
  from typing import (
5
7
  Any,
8
+ Awaitable,
6
9
  Callable,
10
+ Deque,
7
11
  Dict,
8
12
  Generic,
9
13
  Iterable,
@@ -252,3 +256,94 @@ class ListResponse(List[TModelBase]):
252
256
  return
253
257
  if index >= len(self) and self.has_more:
254
258
  self._fetch_next_page()
259
+
260
+
261
+ RT = TypeVar("RT")
262
+
263
+
264
+ class ResultIterator(Generic[RT]):
265
+ """
266
+ Lazily fetch and parse pages from a paged-list API that returns
267
+ Pydantic models with `.results` and `.metadata.next_paging_token`.
268
+ """
269
+
270
+ def __init__(
271
+ self,
272
+ *,
273
+ page_token: Optional[str],
274
+ max_items: Optional[int],
275
+ fetch_page: Callable[[Optional[str]], Any],
276
+ parse_fn: Optional[Callable[[Any], RT]] = None,
277
+ async_parse_fn: Optional[Callable[[Any], Awaitable[RT]]] = None,
278
+ ):
279
+ if parse_fn and async_parse_fn:
280
+ raise ValueError("Only one of parse_fn or async_parse_fn may be provided")
281
+
282
+ self._token = page_token
283
+ self._max = max_items
284
+ self._fetch = fetch_page
285
+ self._parse = parse_fn
286
+ self._aparse = async_parse_fn
287
+ self._buffer: Deque[RT] = deque()
288
+ self._count = 0
289
+ self._finished = False
290
+
291
+ def __iter__(self) -> Iterator[RT]:
292
+ while True:
293
+ # 1) Drain the buffer
294
+ while self._buffer:
295
+ if self._max is not None and self._count >= self._max:
296
+ return
297
+ self._count += 1
298
+ yield self._buffer.popleft()
299
+
300
+ # 2) Done?
301
+ if self._finished or (self._max is not None and self._count >= self._max):
302
+ return
303
+
304
+ # 3) Fetch the next page (Pydantic model)
305
+ page = self._fetch(self._token)
306
+ raw_results = page.results
307
+ self._token = page.metadata.next_paging_token
308
+
309
+ # 4) No more data?
310
+ if not raw_results:
311
+ self._finished = True
312
+ return
313
+
314
+ # 5) Parse—sync or async
315
+ if self._aparse:
316
+ processed = asyncio.run(
317
+ ResultIterator._process_items_async(raw_results, self._aparse)
318
+ )
319
+ self._buffer.extend(processed)
320
+
321
+ elif self._parse:
322
+ try:
323
+ for raw in raw_results:
324
+ self._buffer.append(self._parse(raw))
325
+ except Exception as e: # noqa: BLE001
326
+ raise RuntimeError(f"sync parse error: {e}") from e
327
+
328
+ else:
329
+ # No parser: assume items are already RT
330
+ self._buffer.extend(raw_results) # type: ignore
331
+
332
+ # 6) If no next token, finish on next loop
333
+ if self._token is None:
334
+ self._finished = True
335
+
336
+ @staticmethod
337
+ async def _process_items_async(
338
+ items: List[Any], parser: Callable[[Any], Awaitable[RT]],
339
+ ) -> List[RT]:
340
+ if not items:
341
+ return []
342
+ tasks = [parser(item) for item in items]
343
+ results = await asyncio.gather(*tasks, return_exceptions=True)
344
+ processed: List[RT] = []
345
+ for idx, res in enumerate(results):
346
+ if isinstance(res, Exception):
347
+ raise RuntimeError(f"async parse failed on item {idx}: {res}") from res
348
+ processed.append(res)
349
+ return processed
@@ -328,4 +328,6 @@ class WorkloadSDK(BaseSDK):
328
328
  if not compute_config.anonymous:
329
329
  return compute_config_name
330
330
 
331
- return self._compute_config_sdk.get_compute_config(id=compute_config_id).config
331
+ return self._compute_config_sdk._convert_api_model_to_compute_config_version( # noqa: SLF001
332
+ compute_config
333
+ ).config
@@ -15,9 +15,9 @@ import anyscale
15
15
  from anyscale.aggregated_instance_usage.models import DownloadCSVFilters
16
16
 
17
17
  download_csv_filters = DownloadCSVFilters(
18
- # Start date (inclusive) for the usage CSV.
18
+ # Start date (UTC inclusive) for the usage CSV.
19
19
  start_date="2024-10-01",
20
- # End date (inclusive) for the usage CSV.
20
+ # End date (UTC inclusive) for the usage CSV.
21
21
  end_date="2024-10-31",
22
22
  # Optional cloud name to filter by.
23
23
  cloud="cloud_name",
@@ -39,14 +39,14 @@ download_csv_filters = DownloadCSVFilters(
39
39
  raise ValueError("Incorrect date format, should be YYYY-MM-DD")
40
40
 
41
41
  start_date: str = field(
42
- metadata={"docstring": "Start date (inclusive) for the usage CSV."}
42
+ metadata={"docstring": "Start date (UTC inclusive) for the usage CSV."}
43
43
  )
44
44
 
45
45
  def _validate_start_date(self, start_date: str):
46
46
  self._validate_date(start_date)
47
47
 
48
48
  end_date: str = field(
49
- metadata={"docstring": "End date (inclusive) for the usage CSV."}
49
+ metadata={"docstring": "End date (UTC inclusive) for the usage CSV."}
50
50
  )
51
51
 
52
52
  def _validate_end_date(self, end_date: str):
anyscale/client/README.md CHANGED
@@ -294,6 +294,7 @@ Class | Method | HTTP request | Description
294
294
  *DefaultApi* | [**list_project_collaborators_api_v2_projects_project_id_collaborators_users_get**](docs/DefaultApi.md#list_project_collaborators_api_v2_projects_project_id_collaborators_users_get) | **GET** /api/v2/projects/{project_id}/collaborators/users | List Project Collaborators
295
295
  *DefaultApi* | [**list_projects_api_v2_projects_get**](docs/DefaultApi.md#list_projects_api_v2_projects_get) | **GET** /api/v2/projects/ | List Projects
296
296
  *DefaultApi* | [**list_ray_sessions_api_v2_tasks_dashboard_list_ray_sessions_get**](docs/DefaultApi.md#list_ray_sessions_api_v2_tasks_dashboard_list_ray_sessions_get) | **GET** /api/v2/tasks_dashboard/list_ray_sessions | List Ray Sessions
297
+ *DefaultApi* | [**list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get**](docs/DefaultApi.md#list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get) | **GET** /api/v2/experimental_workspaces/templates/recommended | List Recommended Workspace Templates
297
298
  *DefaultApi* | [**list_services_api_v2_services_v2_get**](docs/DefaultApi.md#list_services_api_v2_services_v2_get) | **GET** /api/v2/services-v2/ | List Services
298
299
  *DefaultApi* | [**list_sessions_api_v2_sessions_get**](docs/DefaultApi.md#list_sessions_api_v2_sessions_get) | **GET** /api/v2/sessions/ | List Sessions
299
300
  *DefaultApi* | [**list_workspace_templates_api_v2_experimental_workspaces_templates_get**](docs/DefaultApi.md#list_workspace_templates_api_v2_experimental_workspaces_templates_get) | **GET** /api/v2/experimental_workspaces/templates | List Workspace Templates
@@ -20980,6 +20980,7 @@ class DefaultApi(object):
20980
20980
 
20981
20981
  :param async_req bool: execute request asynchronously
20982
20982
  :param str cluster_id: (required)
20983
+ :param bool skip_job_details: Skip decorating job details, which can be an expensive operation.
20983
20984
  :param _preload_content: if False, the urllib3.HTTPResponse object will
20984
20985
  be returned without reading/decoding response
20985
20986
  data. Default is True.
@@ -21004,6 +21005,7 @@ class DefaultApi(object):
21004
21005
 
21005
21006
  :param async_req bool: execute request asynchronously
21006
21007
  :param str cluster_id: (required)
21008
+ :param bool skip_job_details: Skip decorating job details, which can be an expensive operation.
21007
21009
  :param _return_http_data_only: response data without head status code
21008
21010
  and headers
21009
21011
  :param _preload_content: if False, the urllib3.HTTPResponse object will
@@ -21021,7 +21023,8 @@ class DefaultApi(object):
21021
21023
  local_var_params = locals()
21022
21024
 
21023
21025
  all_params = [
21024
- 'cluster_id'
21026
+ 'cluster_id',
21027
+ 'skip_job_details'
21025
21028
  ]
21026
21029
  all_params.extend(
21027
21030
  [
@@ -21052,6 +21055,8 @@ class DefaultApi(object):
21052
21055
  query_params = []
21053
21056
  if 'cluster_id' in local_var_params and local_var_params['cluster_id'] is not None: # noqa: E501
21054
21057
  query_params.append(('cluster_id', local_var_params['cluster_id'])) # noqa: E501
21058
+ if 'skip_job_details' in local_var_params and local_var_params['skip_job_details'] is not None: # noqa: E501
21059
+ query_params.append(('skip_job_details', local_var_params['skip_job_details'])) # noqa: E501
21055
21060
 
21056
21061
  header_params = {}
21057
21062
 
@@ -26320,6 +26325,122 @@ class DefaultApi(object):
26320
26325
  _request_timeout=local_var_params.get('_request_timeout'),
26321
26326
  collection_formats=collection_formats)
26322
26327
 
26328
+ def list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get(self, **kwargs): # noqa: E501
26329
+ """List Recommended Workspace Templates # noqa: E501
26330
+
26331
+ Lists all workspace templates ranked by user's organization marketing questions # noqa: E501
26332
+ This method makes a synchronous HTTP request by default. To make an
26333
+ asynchronous HTTP request, please pass async_req=True
26334
+ >>> thread = api.list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get(async_req=True)
26335
+ >>> result = thread.get()
26336
+
26337
+ :param async_req bool: execute request asynchronously
26338
+ :param int count: Maximum number of templates to return
26339
+ :param list[str] oa_group_names: Search for templates that belong to the provided group name
26340
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
26341
+ be returned without reading/decoding response
26342
+ data. Default is True.
26343
+ :param _request_timeout: timeout setting for this request. If one
26344
+ number provided, it will be total request
26345
+ timeout. It can also be a pair (tuple) of
26346
+ (connection, read) timeouts.
26347
+ :return: WorkspacetemplateListResponse
26348
+ If the method is called asynchronously,
26349
+ returns the request thread.
26350
+ """
26351
+ kwargs['_return_http_data_only'] = True
26352
+ return self.list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get_with_http_info(**kwargs) # noqa: E501
26353
+
26354
+ def list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get_with_http_info(self, **kwargs): # noqa: E501
26355
+ """List Recommended Workspace Templates # noqa: E501
26356
+
26357
+ Lists all workspace templates ranked by user's organization marketing questions # noqa: E501
26358
+ This method makes a synchronous HTTP request by default. To make an
26359
+ asynchronous HTTP request, please pass async_req=True
26360
+ >>> thread = api.list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get_with_http_info(async_req=True)
26361
+ >>> result = thread.get()
26362
+
26363
+ :param async_req bool: execute request asynchronously
26364
+ :param int count: Maximum number of templates to return
26365
+ :param list[str] oa_group_names: Search for templates that belong to the provided group name
26366
+ :param _return_http_data_only: response data without head status code
26367
+ and headers
26368
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
26369
+ be returned without reading/decoding response
26370
+ data. Default is True.
26371
+ :param _request_timeout: timeout setting for this request. If one
26372
+ number provided, it will be total request
26373
+ timeout. It can also be a pair (tuple) of
26374
+ (connection, read) timeouts.
26375
+ :return: tuple(WorkspacetemplateListResponse, status_code(int), headers(HTTPHeaderDict))
26376
+ If the method is called asynchronously,
26377
+ returns the request thread.
26378
+ """
26379
+
26380
+ local_var_params = locals()
26381
+
26382
+ all_params = [
26383
+ 'count',
26384
+ 'oa_group_names'
26385
+ ]
26386
+ all_params.extend(
26387
+ [
26388
+ 'async_req',
26389
+ '_return_http_data_only',
26390
+ '_preload_content',
26391
+ '_request_timeout'
26392
+ ]
26393
+ )
26394
+
26395
+ for key, val in six.iteritems(local_var_params['kwargs']):
26396
+ if key not in all_params:
26397
+ raise ApiTypeError(
26398
+ "Got an unexpected keyword argument '%s'"
26399
+ " to method list_recommended_workspace_templates_api_v2_experimental_workspaces_templates_recommended_get" % key
26400
+ )
26401
+ local_var_params[key] = val
26402
+ del local_var_params['kwargs']
26403
+
26404
+ collection_formats = {}
26405
+
26406
+ path_params = {}
26407
+
26408
+ query_params = []
26409
+ if 'count' in local_var_params and local_var_params['count'] is not None: # noqa: E501
26410
+ query_params.append(('count', local_var_params['count'])) # noqa: E501
26411
+ if 'oa_group_names' in local_var_params and local_var_params['oa_group_names'] is not None: # noqa: E501
26412
+ query_params.append(('oa_group_names', local_var_params['oa_group_names'])) # noqa: E501
26413
+ collection_formats['oa_group_names'] = 'multi' # noqa: E501
26414
+
26415
+ header_params = {}
26416
+
26417
+ form_params = []
26418
+ local_var_files = {}
26419
+
26420
+ body_params = None
26421
+ # HTTP header `Accept`
26422
+ header_params['Accept'] = self.api_client.select_header_accept(
26423
+ ['application/json']) # noqa: E501
26424
+
26425
+ # Authentication setting
26426
+ auth_settings = [] # noqa: E501
26427
+
26428
+ return self.api_client.call_api(
26429
+ '/api/v2/experimental_workspaces/templates/recommended', 'GET',
26430
+ path_params,
26431
+ query_params,
26432
+ header_params,
26433
+ body=body_params,
26434
+ post_params=form_params,
26435
+ files=local_var_files,
26436
+ response_type='WorkspacetemplateListResponse', # noqa: E501
26437
+ auth_settings=auth_settings,
26438
+ async_req=local_var_params.get('async_req'),
26439
+ _return_http_data_only=local_var_params.get('_return_http_data_only'), # noqa: E501
26440
+ _preload_content=local_var_params.get('_preload_content', True),
26441
+ _request_timeout=local_var_params.get('_request_timeout'),
26442
+ collection_formats=collection_formats)
26443
+
26323
26444
  def list_services_api_v2_services_v2_get(self, **kwargs): # noqa: E501
26324
26445
  """List Services # noqa: E501
26325
26446