anyscale 0.24.88__py3-none-any.whl → 0.25.5__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 (148) hide show
  1. anyscale/__init__.py +56 -0
  2. anyscale/_private/anyscale_client/anyscale_client.py +179 -28
  3. anyscale/_private/anyscale_client/common.py +109 -2
  4. anyscale/_private/anyscale_client/fake_anyscale_client.py +239 -1
  5. anyscale/_private/docgen/README.md +1 -1
  6. anyscale/_private/docgen/__main__.py +71 -21
  7. anyscale/_private/docgen/api.md +13 -20
  8. anyscale/_private/docgen/generator.py +3 -2
  9. anyscale/_private/docgen/models.md +4 -49
  10. anyscale/_private/workload/workload_config.py +21 -7
  11. anyscale/aggregated_instance_usage/__init__.py +1 -1
  12. anyscale/aggregated_instance_usage/commands.py +2 -4
  13. anyscale/aggregated_instance_usage/models.py +8 -8
  14. anyscale/client/README.md +25 -22
  15. anyscale/client/openapi_client/__init__.py +16 -14
  16. anyscale/client/openapi_client/api/default_api.py +1139 -959
  17. anyscale/client/openapi_client/models/__init__.py +16 -14
  18. anyscale/client/openapi_client/models/baseimagesenum.py +43 -1
  19. anyscale/client/openapi_client/models/{session_event_types.py → cloud_deployment_config.py} +35 -24
  20. anyscale/client/openapi_client/models/{platformfinetuningjob_response.py → clouddeploymentconfig_response.py} +11 -11
  21. anyscale/client/openapi_client/models/{log_level_types.py → cluster_event_source.py} +12 -7
  22. anyscale/client/openapi_client/models/{company_size.py → cluster_size.py} +10 -10
  23. anyscale/client/openapi_client/models/cluster_status_details.py +2 -1
  24. anyscale/client/openapi_client/models/{sessionevent_list_response.py → clusterevent_list_response.py} +15 -15
  25. anyscale/client/openapi_client/models/create_experimental_workspace.py +29 -1
  26. anyscale/client/openapi_client/models/create_notification_channel_record.py +29 -3
  27. anyscale/client/openapi_client/models/decorated_interactive_session.py +1 -57
  28. anyscale/client/openapi_client/models/decorated_job.py +1 -57
  29. anyscale/client/openapi_client/models/decorated_job_submission.py +1 -29
  30. anyscale/client/openapi_client/models/decorated_production_job.py +1 -29
  31. anyscale/client/openapi_client/models/decorated_session.py +1 -57
  32. anyscale/client/openapi_client/models/decorated_unified_job.py +1 -30
  33. anyscale/client/openapi_client/models/{resubmit_ft_job_request.py → describe_machine_pool_request.py} +21 -20
  34. anyscale/client/openapi_client/models/describe_machine_pool_response.py +123 -0
  35. anyscale/client/openapi_client/models/describemachinepoolresponse_response.py +121 -0
  36. anyscale/client/openapi_client/models/ha_jobs_sort_field.py +1 -2
  37. anyscale/client/openapi_client/models/internal_production_job.py +1 -29
  38. anyscale/client/openapi_client/models/jobs_sort_field.py +1 -2
  39. anyscale/client/openapi_client/models/machine_allocation_state.py +3 -1
  40. anyscale/client/openapi_client/models/machine_state_info.py +326 -0
  41. anyscale/client/openapi_client/models/{fine_tuning_job_status.py → notification_channel_slack_config.py} +34 -16
  42. anyscale/client/openapi_client/models/organization_marketing_questions.py +80 -54
  43. anyscale/client/openapi_client/models/request_state_info.py +210 -0
  44. anyscale/client/openapi_client/models/{platformfinetuningjob_list_response.py → scheduler_info.py} +43 -38
  45. anyscale/client/openapi_client/models/serve_deployment_fast_api_docs_status.py +123 -0
  46. anyscale/client/openapi_client/models/serve_deployment_state.py +2 -1
  47. anyscale/client/openapi_client/models/servedeploymentfastapidocsstatus_response.py +121 -0
  48. anyscale/client/openapi_client/models/sessions_sort_field.py +1 -2
  49. anyscale/client/openapi_client/models/supportedbaseimagesenum.py +43 -1
  50. anyscale/client/openapi_client/models/unified_job_sort_field.py +1 -2
  51. anyscale/client/openapi_client/models/update_cloud_collaborator.py +121 -0
  52. anyscale/client/openapi_client/models/usage_by_cluster.py +28 -1
  53. anyscale/client/openapi_client/models/usage_by_user.py +30 -3
  54. anyscale/client/openapi_client/models/workload_info.py +210 -0
  55. anyscale/cloud/__init__.py +83 -0
  56. anyscale/cloud/_private/cloud_sdk.py +25 -0
  57. anyscale/cloud/commands.py +45 -0
  58. anyscale/cloud/models.py +91 -0
  59. anyscale/cluster_compute.py +1 -1
  60. anyscale/commands/aggregated_instance_usage_commands.py +4 -4
  61. anyscale/commands/cloud_commands.py +87 -14
  62. anyscale/commands/command_examples.py +65 -0
  63. anyscale/commands/job_commands.py +15 -3
  64. anyscale/commands/machine_pool_commands.py +113 -1
  65. anyscale/commands/organization_invitation_commands.py +98 -0
  66. anyscale/commands/project_commands.py +52 -2
  67. anyscale/commands/resource_quota_commands.py +98 -11
  68. anyscale/commands/service_account_commands.py +65 -8
  69. anyscale/commands/service_commands.py +61 -1
  70. anyscale/commands/session_commands_hidden.py +5 -1
  71. anyscale/commands/user_commands.py +1 -1
  72. anyscale/commands/util.py +2 -2
  73. anyscale/commands/workspace_commands.py +1 -1
  74. anyscale/connect.py +1 -1
  75. anyscale/connect_utils/project.py +7 -4
  76. anyscale/controllers/cloud_controller.py +63 -30
  77. anyscale/controllers/cloud_functional_verification_controller.py +1 -1
  78. anyscale/controllers/cluster_controller.py +3 -11
  79. anyscale/controllers/compute_config_controller.py +1 -1
  80. anyscale/controllers/experimental_integrations_controller.py +1 -1
  81. anyscale/controllers/job_controller.py +8 -6
  82. anyscale/controllers/list_controller.py +2 -2
  83. anyscale/controllers/machine_pool_controller.py +12 -1
  84. anyscale/controllers/project_controller.py +4 -3
  85. anyscale/controllers/schedule_controller.py +1 -1
  86. anyscale/controllers/service_controller.py +1 -1
  87. anyscale/controllers/workspace_controller.py +1 -1
  88. anyscale/models/job_model.py +1 -1
  89. anyscale/organization_invitation/__init__.py +61 -0
  90. anyscale/organization_invitation/_private/organization_invitation_sdk.py +24 -0
  91. anyscale/organization_invitation/commands.py +84 -0
  92. anyscale/organization_invitation/models.py +45 -0
  93. anyscale/project/__init__.py +35 -0
  94. anyscale/project/_private/project_sdk.py +27 -0
  95. anyscale/project/commands.py +56 -0
  96. anyscale/project/models.py +91 -0
  97. anyscale/{project.py → project_utils.py} +3 -4
  98. anyscale/resource_quota/__init__.py +99 -0
  99. anyscale/resource_quota/_private/resource_quota_sdk.py +120 -0
  100. anyscale/resource_quota/commands.py +150 -0
  101. anyscale/resource_quota/models.py +303 -0
  102. anyscale/scripts.py +4 -0
  103. anyscale/sdk/anyscale_client/__init__.py +0 -5
  104. anyscale/sdk/anyscale_client/api/default_api.py +119 -150
  105. anyscale/sdk/anyscale_client/models/__init__.py +0 -5
  106. anyscale/sdk/anyscale_client/models/baseimagesenum.py +43 -1
  107. anyscale/sdk/anyscale_client/models/cluster_status_details.py +2 -1
  108. anyscale/sdk/anyscale_client/models/jobs_sort_field.py +1 -2
  109. anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +43 -1
  110. anyscale/sdk/anyscale_client/sdk.py +1 -1
  111. anyscale/service/__init__.py +21 -0
  112. anyscale/service/_private/service_sdk.py +13 -0
  113. anyscale/service/commands.py +35 -0
  114. anyscale/service_account/__init__.py +88 -0
  115. anyscale/service_account/_private/service_account_sdk.py +101 -0
  116. anyscale/service_account/commands.py +147 -0
  117. anyscale/service_account/models.py +66 -0
  118. anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
  119. anyscale/shared_anyscale_utils/utils/id_gen.py +2 -0
  120. anyscale/user/__init__.py +1 -1
  121. anyscale/user/commands.py +1 -1
  122. anyscale/user/models.py +25 -15
  123. anyscale/util.py +23 -0
  124. anyscale/utils/cloud_utils.py +1 -1
  125. anyscale/version.py +1 -1
  126. anyscale/workspace_utils.py +1 -1
  127. {anyscale-0.24.88.dist-info → anyscale-0.25.5.dist-info}/METADATA +1 -5
  128. {anyscale-0.24.88.dist-info → anyscale-0.25.5.dist-info}/RECORD +134 -119
  129. anyscale/client/openapi_client/models/create_fine_tuning_hyperparameters.py +0 -156
  130. anyscale/client/openapi_client/models/create_fine_tuning_job_product_request.py +0 -353
  131. anyscale/client/openapi_client/models/finish_ft_job_request.py +0 -204
  132. anyscale/client/openapi_client/models/platform_fine_tuning_job.py +0 -577
  133. anyscale/client/openapi_client/models/session_event.py +0 -267
  134. anyscale/client/openapi_client/models/session_event_cause.py +0 -150
  135. anyscale/controllers/resource_quota_controller.py +0 -183
  136. anyscale/controllers/service_account_controller.py +0 -168
  137. anyscale/sdk/anyscale_client/models/log_level_types.py +0 -100
  138. anyscale/sdk/anyscale_client/models/session_event.py +0 -267
  139. anyscale/sdk/anyscale_client/models/session_event_cause.py +0 -150
  140. anyscale/sdk/anyscale_client/models/session_event_types.py +0 -111
  141. anyscale/sdk/anyscale_client/models/sessionevent_list_response.py +0 -147
  142. anyscale/utils/imports/azure.py +0 -14
  143. /anyscale/{cloud.py → cloud_utils.py} +0 -0
  144. {anyscale-0.24.88.dist-info → anyscale-0.25.5.dist-info}/LICENSE +0 -0
  145. {anyscale-0.24.88.dist-info → anyscale-0.25.5.dist-info}/NOTICE +0 -0
  146. {anyscale-0.24.88.dist-info → anyscale-0.25.5.dist-info}/WHEEL +0 -0
  147. {anyscale-0.24.88.dist-info → anyscale-0.25.5.dist-info}/entry_points.txt +0 -0
  148. {anyscale-0.24.88.dist-info → anyscale-0.25.5.dist-info}/top_level.txt +0 -0
@@ -9,10 +9,10 @@ from typing import Any, Dict, List, Optional, Tuple
9
9
  import tabulate
10
10
 
11
11
  from anyscale.cli_logger import BlockLogger
12
- from anyscale.cloud import get_cloud_json_from_id
12
+ from anyscale.cloud_utils import get_cloud_json_from_id
13
13
  from anyscale.controllers.base_controller import BaseController
14
14
  from anyscale.formatters import clouds_formatter
15
- from anyscale.project import (
15
+ from anyscale.project_utils import (
16
16
  get_project_id,
17
17
  load_project_or_throw,
18
18
  )
@@ -10,11 +10,13 @@ from anyscale.client.openapi_client.models import (
10
10
  CreateMachinePoolRequest,
11
11
  CreateMachinePoolResponse,
12
12
  DeleteMachinePoolRequest,
13
+ DescribeMachinePoolRequest,
14
+ DescribeMachinePoolResponse,
13
15
  DetachMachinePoolFromCloudRequest,
14
16
  ListMachinePoolsResponse,
15
17
  UpdateMachinePoolRequest,
16
18
  )
17
- from anyscale.cloud import get_cloud_id_and_name
19
+ from anyscale.cloud_utils import get_cloud_id_and_name
18
20
  from anyscale.controllers.base_controller import BaseController
19
21
 
20
22
 
@@ -65,6 +67,15 @@ class MachinePoolController(BaseController):
65
67
  UpdateMachinePoolRequest(machine_pool_name=machine_pool_name, spec=spec,)
66
68
  )
67
69
 
70
+ def describe_machine_pool(
71
+ self, machine_pool_name: str,
72
+ ) -> DescribeMachinePoolResponse:
73
+ return self.api_client.describe_machine_pool_api_v2_machine_pools_describe_post(
74
+ describe_machine_pool_request=DescribeMachinePoolRequest(
75
+ machine_pool_name=machine_pool_name,
76
+ )
77
+ ).result
78
+
68
79
  def list_machine_pools(self,) -> ListMachinePoolsResponse:
69
80
  response = self.api_client.list_machine_pools_api_v2_machine_pools_get().result
70
81
  return response
@@ -8,9 +8,10 @@ import tabulate
8
8
 
9
9
  import anyscale
10
10
  from anyscale.cli_logger import BlockLogger
11
- from anyscale.cloud import get_cloud_id_and_name
11
+ from anyscale.cloud_utils import get_cloud_id_and_name
12
12
  from anyscale.controllers.base_controller import BaseController
13
- from anyscale.project import ( # pylint:disable=private-import
13
+ import anyscale.project_utils
14
+ from anyscale.project_utils import ( # pylint:disable=private-import
14
15
  attach_to_project_with_id,
15
16
  create_new_proj_def,
16
17
  get_proj_id_from_name,
@@ -102,7 +103,7 @@ class ProjectController(BaseController):
102
103
  "and compute configs."
103
104
  )
104
105
  self.log.warning(message)
105
- project_id_path = anyscale.project.ANYSCALE_PROJECT_FILE
106
+ project_id_path = anyscale.project_utils.ANYSCALE_PROJECT_FILE
106
107
 
107
108
  if project_id:
108
109
  # Exactly one of project_id or name must be provided
@@ -22,7 +22,7 @@ from anyscale.client.openapi_client.models.schedule_config import (
22
22
  )
23
23
  from anyscale.controllers.base_controller import BaseController
24
24
  from anyscale.models.job_model import JobConfig
25
- from anyscale.project import infer_project_id
25
+ from anyscale.project_utils import infer_project_id
26
26
  from anyscale.tables import SchedulesTable
27
27
  from anyscale.util import (
28
28
  AnyscaleEndpointFormatter,
@@ -19,7 +19,7 @@ from anyscale.client.openapi_client.models.decorated_production_service_v2_api_m
19
19
  )
20
20
  from anyscale.controllers.base_controller import BaseController
21
21
  from anyscale.models.service_model import ServiceConfig
22
- from anyscale.project import infer_project_id
22
+ from anyscale.project_utils import infer_project_id
23
23
  from anyscale.sdk.anyscale_client.models import (
24
24
  ApplyServiceModel,
25
25
  RollbackServiceModel,
@@ -15,7 +15,7 @@ from anyscale.client.openapi_client.models.experimental_workspace import (
15
15
  )
16
16
  from anyscale.controllers.base_controller import BaseController
17
17
  from anyscale.feature_flags import FLAG_DEFAULT_WORKING_DIR_FOR_PROJ
18
- from anyscale.project import get_default_project
18
+ from anyscale.project_utils import get_default_project
19
19
  from anyscale.util import get_endpoint
20
20
  from anyscale.utils.workspace_utils import (
21
21
  extract_workspace_parameters,
@@ -23,7 +23,7 @@ from anyscale.cluster_env import (
23
23
  get_default_cluster_env_build,
24
24
  validate_successful_build,
25
25
  )
26
- from anyscale.project import (
26
+ from anyscale.project_utils import (
27
27
  get_parent_cloud_id_and_name_of_project,
28
28
  get_proj_id_from_name,
29
29
  )
@@ -0,0 +1,61 @@
1
+ from typing import List, Optional
2
+
3
+ from anyscale._private.anyscale_client import AnyscaleClientInterface
4
+ from anyscale._private.sdk import sdk_docs
5
+ from anyscale._private.sdk.base_sdk import Timer
6
+ from anyscale.cli_logger import BlockLogger
7
+ from anyscale.organization_invitation._private.organization_invitation_sdk import (
8
+ PrivateOrganizationInvitationSDK,
9
+ )
10
+ from anyscale.organization_invitation.commands import (
11
+ _CREATE_ARG_DOCSTRINGS,
12
+ _CREATE_EXAMPLE,
13
+ _DELETE_ARG_DOCSTRINGS,
14
+ _DELETE_EXAMPLE,
15
+ _LIST_ARG_DOCSTRINGS,
16
+ _LIST_EXAMPLE,
17
+ create,
18
+ delete,
19
+ list,
20
+ )
21
+
22
+
23
+ class OrganizationInvitationSDK:
24
+ def __init__(
25
+ self,
26
+ *,
27
+ client: Optional[AnyscaleClientInterface] = None,
28
+ logger: Optional[BlockLogger] = None,
29
+ timer: Optional[Timer] = None,
30
+ ):
31
+ self._private_sdk = PrivateOrganizationInvitationSDK(
32
+ client=client, logger=logger, timer=timer
33
+ )
34
+
35
+ @sdk_docs(
36
+ doc_py_example=_CREATE_EXAMPLE, arg_docstrings=_CREATE_ARG_DOCSTRINGS,
37
+ )
38
+ def create( # noqa: F811
39
+ self, emails: List[str],
40
+ ):
41
+ """Creates organization invitations for the provided emails
42
+ """
43
+ return self._private_sdk.create(emails=emails)
44
+
45
+ @sdk_docs(
46
+ doc_py_example=_LIST_EXAMPLE, arg_docstrings=_LIST_ARG_DOCSTRINGS,
47
+ )
48
+ def list(self): # noqa: F811
49
+ """Lists organization invitations
50
+ """
51
+ return self._private_sdk.list()
52
+
53
+ @sdk_docs(
54
+ doc_py_example=_DELETE_EXAMPLE, arg_docstrings=_DELETE_ARG_DOCSTRINGS,
55
+ )
56
+ def delete( # noqa: F811
57
+ self, email: str,
58
+ ):
59
+ """Deletes an organization invitation
60
+ """
61
+ return self._private_sdk.delete(email=email)
@@ -0,0 +1,24 @@
1
+ from typing import List, Tuple
2
+
3
+ from anyscale._private.sdk.base_sdk import BaseSDK
4
+ from anyscale.organization_invitation.models import OrganizationInvitation
5
+
6
+
7
+ class PrivateOrganizationInvitationSDK(BaseSDK):
8
+ def create(self, emails: List[str]) -> Tuple[List[str], List[str]]:
9
+ return self.client.create_organization_invitations(emails=emails)
10
+
11
+ def list(self) -> List[OrganizationInvitation]:
12
+ invitations = self.client.list_organization_invitations()
13
+ return [
14
+ OrganizationInvitation(
15
+ id=invitation.id,
16
+ email=invitation.email,
17
+ created_at=invitation.created_at,
18
+ expires_at=invitation.expires_at,
19
+ )
20
+ for invitation in invitations
21
+ ]
22
+
23
+ def delete(self, email: str) -> str:
24
+ return self.client.delete_organization_invitation(email=email).email
@@ -0,0 +1,84 @@
1
+ from typing import Dict, List, Tuple
2
+
3
+ from anyscale._private.sdk import sdk_command
4
+ from anyscale.organization_invitation._private.organization_invitation_sdk import (
5
+ PrivateOrganizationInvitationSDK,
6
+ )
7
+ from anyscale.organization_invitation.models import OrganizationInvitation
8
+
9
+
10
+ _ORGANIZATION_INVITATION_SDK_SINGLETON_KEY = "organization_invitation_sdk"
11
+
12
+ _CREATE_EXAMPLE = """
13
+ import anyscale
14
+
15
+ anyscale.organization_invitation.create(emails=["test1@anyscale.com","test2@anyscale.com"])
16
+ """
17
+
18
+ _CREATE_ARG_DOCSTRINGS = {
19
+ "emails": "The emails to send the organization invitations to."
20
+ }
21
+
22
+ _LIST_EXAMPLE = """
23
+ import anyscale
24
+
25
+ anyscale.organization_invitation.list()
26
+ """
27
+
28
+ _LIST_ARG_DOCSTRINGS: Dict[str, str] = {}
29
+
30
+ _DELETE_EXAMPLE = """
31
+ import anyscale
32
+
33
+ anyscale.organization_invitation.delete(email="test@anyscale.com")
34
+ """
35
+
36
+ _DELETE_ARG_DOCSTRINGS = {
37
+ "email": "The email of the organization invitation to delete."
38
+ }
39
+
40
+
41
+ @sdk_command(
42
+ _ORGANIZATION_INVITATION_SDK_SINGLETON_KEY,
43
+ PrivateOrganizationInvitationSDK,
44
+ doc_py_example=_CREATE_EXAMPLE,
45
+ arg_docstrings=_CREATE_ARG_DOCSTRINGS,
46
+ )
47
+ def create(
48
+ emails: List[str], *, _sdk: PrivateOrganizationInvitationSDK
49
+ ) -> Tuple[List[str], List[str]]:
50
+ """Creates organization invitations for the provided emails.
51
+
52
+ Returns a tuple of successful emails and error messages.
53
+ """
54
+ return _sdk.create(emails=emails)
55
+
56
+
57
+ @sdk_command(
58
+ _ORGANIZATION_INVITATION_SDK_SINGLETON_KEY,
59
+ PrivateOrganizationInvitationSDK,
60
+ doc_py_example=_LIST_EXAMPLE,
61
+ arg_docstrings=_LIST_ARG_DOCSTRINGS,
62
+ )
63
+ def list( # noqa: A001
64
+ *, _sdk: PrivateOrganizationInvitationSDK
65
+ ) -> List[OrganizationInvitation]:
66
+ """Lists organization invitations.
67
+
68
+ Returns a list of organization invitations.
69
+ """
70
+ return _sdk.list()
71
+
72
+
73
+ @sdk_command(
74
+ _ORGANIZATION_INVITATION_SDK_SINGLETON_KEY,
75
+ PrivateOrganizationInvitationSDK,
76
+ doc_py_example=_DELETE_EXAMPLE,
77
+ arg_docstrings=_DELETE_ARG_DOCSTRINGS,
78
+ )
79
+ def delete(email: str, *, _sdk: PrivateOrganizationInvitationSDK) -> str:
80
+ """Deletes an organization invitation.
81
+
82
+ Returns the email of the deleted organization invitation.
83
+ """
84
+ return _sdk.delete(email)
@@ -0,0 +1,45 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime
3
+
4
+ from anyscale._private.models import ModelBase
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class OrganizationInvitation(ModelBase):
9
+ """Organization invitation model.
10
+ """
11
+
12
+ __doc_py_example__ = """\
13
+ import anyscale
14
+ from anyscale.organization_invitation.models import OrganizationInvitation
15
+
16
+ organization_invitations: List[OrganizationInvitation] = anyscale.organization_invitation.list()
17
+ """
18
+
19
+ id: str = field(metadata={"docstring": "ID of the organization invitation."},)
20
+
21
+ def _validate_id(self, id: str): # noqa: A002
22
+ if not isinstance(id, str):
23
+ raise TypeError("id must be a string.")
24
+
25
+ email: str = field(metadata={"docstring": "Email of the organization invitation."})
26
+
27
+ def _validate_email(self, email: str):
28
+ if not isinstance(email, str):
29
+ raise TypeError("email must be a string.")
30
+
31
+ created_at: datetime = field(
32
+ metadata={"docstring": "Creation time of the organization invitation."},
33
+ )
34
+
35
+ def _validate_created_at(self, created_at: datetime):
36
+ if not isinstance(created_at, datetime):
37
+ raise TypeError("created_at must be a datetime.")
38
+
39
+ expires_at: datetime = field(
40
+ metadata={"docstring": "Expiration time of the organization invitation."},
41
+ )
42
+
43
+ def _validate_expires_at(self, expires_at: datetime):
44
+ if not isinstance(expires_at, datetime):
45
+ raise TypeError("expires_at must be a datetime.")
@@ -0,0 +1,35 @@
1
+ from typing import List, Optional
2
+
3
+ from anyscale._private.anyscale_client import AnyscaleClientInterface
4
+ from anyscale._private.sdk import sdk_docs
5
+ from anyscale._private.sdk.base_sdk import Timer
6
+ from anyscale.cli_logger import BlockLogger
7
+ from anyscale.project._private.project_sdk import PrivateProjectSDK
8
+ from anyscale.project.commands import (
9
+ _ADD_COLLABORATORS_DOCSTRINGS,
10
+ _ADD_COLLABORATORS_EXAMPLE,
11
+ add_collaborators,
12
+ )
13
+ from anyscale.project.models import CreateProjectCollaborator
14
+
15
+
16
+ class ProjectSDK:
17
+ def __init__(
18
+ self,
19
+ *,
20
+ client: Optional[AnyscaleClientInterface] = None,
21
+ logger: Optional[BlockLogger] = None,
22
+ timer: Optional[Timer] = None,
23
+ ):
24
+ self._private_sdk = PrivateProjectSDK(client=client, logger=logger, timer=timer)
25
+
26
+ @sdk_docs(
27
+ doc_py_example=_ADD_COLLABORATORS_EXAMPLE,
28
+ arg_docstrings=_ADD_COLLABORATORS_DOCSTRINGS,
29
+ )
30
+ def add_collaborators( # noqa: F811
31
+ self, cloud: str, project: str, collaborators: List[CreateProjectCollaborator],
32
+ ) -> str:
33
+ """Batch add collaborators to a project.
34
+ """
35
+ return self._private_sdk.add_collaborators(cloud, project, collaborators)
@@ -0,0 +1,27 @@
1
+ from typing import List
2
+
3
+ from anyscale._private.sdk.base_sdk import BaseSDK
4
+ from anyscale.client.openapi_client import (
5
+ CreateUserProjectCollaborator,
6
+ CreateUserProjectCollaboratorValue,
7
+ )
8
+ from anyscale.project.models import CreateProjectCollaborator
9
+
10
+
11
+ class PrivateProjectSDK(BaseSDK):
12
+ def add_collaborators(
13
+ self, cloud: str, project: str, collaborators: List[CreateProjectCollaborator]
14
+ ) -> str:
15
+ cloud_id = self.client.get_cloud_id(cloud_name=cloud, compute_config_id=None)
16
+ project_id = self.client.get_project_id(parent_cloud_id=cloud_id, name=project)
17
+
18
+ return self.client.add_project_collaborators(
19
+ project_id=project_id,
20
+ collaborators=[
21
+ CreateUserProjectCollaborator(
22
+ value=CreateUserProjectCollaboratorValue(email=collaborator.email),
23
+ permission_level=collaborator.permission_level.lower(),
24
+ )
25
+ for collaborator in collaborators
26
+ ],
27
+ )
@@ -0,0 +1,56 @@
1
+ from typing import List
2
+
3
+ from anyscale._private.sdk import sdk_command
4
+ from anyscale.project._private.project_sdk import PrivateProjectSDK
5
+ from anyscale.project.models import CreateProjectCollaborator
6
+
7
+
8
+ _PROJECT_SDK_SINGLETON_KEY = "project_sdk"
9
+
10
+ _ADD_COLLABORATORS_EXAMPLE = """
11
+ import anyscale
12
+ from anyscale.project.models import CreateProjectCollaborator, ProjectPermissionLevel
13
+
14
+ anyscale.project.add_collaborators(
15
+ cloud="cloud_name",
16
+ project="project_name",
17
+ collaborators=[
18
+ CreateProjectCollaborator(
19
+ email="test1@anyscale.com",
20
+ permission_level=ProjectPermissionLevel.OWNER,
21
+ ),
22
+ CreateProjectCollaborator(
23
+ email="test2@anyscale.com",
24
+ permission_level=ProjectPermissionLevel.WRITE,
25
+ ),
26
+ CreateProjectCollaborator(
27
+ email="test3@anyscale.com",
28
+ permission_level=ProjectPermissionLevel.READONLY,
29
+ ),
30
+ ],
31
+ )
32
+ """
33
+
34
+ _ADD_COLLABORATORS_DOCSTRINGS = {
35
+ "cloud": "The cloud that the project belongs to.",
36
+ "project": "The project to add users to.",
37
+ "collaborators": "The list of collaborators to add to the project.",
38
+ }
39
+
40
+
41
+ @sdk_command(
42
+ _PROJECT_SDK_SINGLETON_KEY,
43
+ PrivateProjectSDK,
44
+ doc_py_example=_ADD_COLLABORATORS_EXAMPLE,
45
+ arg_docstrings=_ADD_COLLABORATORS_DOCSTRINGS,
46
+ )
47
+ def add_collaborators(
48
+ cloud: str,
49
+ project: str,
50
+ collaborators: List[CreateProjectCollaborator],
51
+ *,
52
+ _sdk: PrivateProjectSDK
53
+ ) -> str:
54
+ """Batch add collaborators to a project.
55
+ """
56
+ return _sdk.add_collaborators(cloud, project, collaborators)
@@ -0,0 +1,91 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, Dict, List
3
+
4
+ from anyscale._private.models import ModelBase, ModelEnum
5
+
6
+
7
+ class ProjectPermissionLevel(ModelEnum):
8
+ OWNER = "OWNER"
9
+ WRITE = "WRITE"
10
+ READONLY = "READONLY"
11
+
12
+ __docstrings__ = {
13
+ OWNER: "Owner permission level for the project",
14
+ WRITE: "Write permission level for the project",
15
+ READONLY: "Readonly permission level for the project",
16
+ }
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class CreateProjectCollaborator(ModelBase):
21
+ """User to be added as a collaborator to a project.
22
+ """
23
+
24
+ __doc_py_example__ = """\
25
+ import anyscale
26
+ from anyscale.project.models import ProjectPermissionLevel, CreateProjectCollaborator
27
+ create_project_collaborator = CreateProjectCollaborator(
28
+ # Email of the user to be added as a collaborator
29
+ email="test@anyscale.com",
30
+ # Permission level for the user to the project (ProjectPermissionLevel.OWNER, ProjectPermissionLevel.WRITE, ProjectPermissionLevel.READONLY)
31
+ permission_level=ProjectPermissionLevel.READONLY,
32
+ )
33
+ """
34
+
35
+ def _validate_email(self, email: str):
36
+ if not isinstance(email, str):
37
+ raise TypeError("Email must be a string.")
38
+
39
+ email: str = field(
40
+ metadata={"docstring": "Email of the user to be added as a collaborator."},
41
+ )
42
+
43
+ def _validate_permission_level(
44
+ self, permission_level: ProjectPermissionLevel
45
+ ) -> ProjectPermissionLevel:
46
+ if isinstance(permission_level, str):
47
+ return ProjectPermissionLevel.validate(permission_level)
48
+ elif isinstance(permission_level, ProjectPermissionLevel):
49
+ return permission_level
50
+ else:
51
+ raise TypeError(
52
+ f"'permission_level' must be a 'ProjectPermissionLevel' (it is {type(permission_level)})."
53
+ )
54
+
55
+ permission_level: ProjectPermissionLevel = field( # type: ignore
56
+ default=ProjectPermissionLevel.READONLY, # type: ignore
57
+ metadata={
58
+ "docstring": "Permission level the added user should have for the project" # type: ignore
59
+ f"(one of: {','.join([str(m.value) for m in ProjectPermissionLevel])}", # type: ignore
60
+ },
61
+ )
62
+
63
+
64
+ @dataclass(frozen=True)
65
+ class CreateProjectCollaborators(ModelBase):
66
+ """List of users to be added as collaborators to a project.
67
+ """
68
+
69
+ __doc_py_example__ = """\
70
+ import anyscale
71
+ from anyscale.project.models import ProjectPermissionLevel, CreateProjectCollaborator, CreateProjectCollaborators
72
+ create_project_collaborator = CreateProjectCollaborator(
73
+ # Email of the user to be added as a collaborator
74
+ email="test@anyscale.com",
75
+ # Permission level for the user to the project (ProjectPermissionLevel.OWNER, ProjectPermissionLevel.WRITE, ProjectPermissionLevel.READONLY)
76
+ permission_level=ProjectPermissionLevel.READONLY,
77
+ )
78
+ create_project_collaborators = CreateProjectCollaborators(
79
+ collaborators=[create_project_collaborator]
80
+ )
81
+ """
82
+
83
+ collaborators: List[Dict[str, Any]] = field(
84
+ metadata={
85
+ "docstring": "List of users to be added as collaborators to a project."
86
+ },
87
+ )
88
+
89
+ def _validate_collaborators(self, collaborators: List[Dict[str, Any]]):
90
+ if not isinstance(collaborators, list):
91
+ raise TypeError("Collaborators must be a list.")
@@ -5,12 +5,11 @@ import click
5
5
  from click import ClickException
6
6
  import yaml
7
7
 
8
- import anyscale
9
8
  from anyscale.authenticate import get_auth_api_client
10
9
  from anyscale.cli_logger import BlockLogger
11
10
  from anyscale.client.openapi_client import Project
12
11
  from anyscale.client.openapi_client.api.default_api import DefaultApi
13
- from anyscale.cloud import get_cloud_id_and_name
12
+ from anyscale.cloud_utils import get_cloud_id_and_name
14
13
  from anyscale.cluster_compute import (
15
14
  get_cluster_compute_from_name,
16
15
  get_selected_cloud_id_or_default,
@@ -301,13 +300,13 @@ def create_new_proj_def(
301
300
  name = slugify(name)
302
301
  log.info(f"Normalized project name to {name}")
303
302
 
304
- project_definition = anyscale.project.ProjectDefinition(os.getcwd())
303
+ project_definition = ProjectDefinition(os.getcwd())
305
304
  project_definition.config["name"] = name
306
305
  return name, project_definition
307
306
 
308
307
 
309
308
  def _do_attach(project_id: str, is_create_project: bool) -> None:
310
- with open(anyscale.project.ANYSCALE_PROJECT_FILE, "w") as f:
309
+ with open(ANYSCALE_PROJECT_FILE, "w") as f:
311
310
  yaml.dump(
312
311
  {"project_id": project_id}, f,
313
312
  )
@@ -0,0 +1,99 @@
1
+ from typing import List, Optional
2
+
3
+ from anyscale._private.anyscale_client import AnyscaleClientInterface
4
+ from anyscale._private.sdk import sdk_docs
5
+ from anyscale._private.sdk.base_sdk import Timer
6
+ from anyscale.cli_logger import BlockLogger
7
+ from anyscale.resource_quota._private.resource_quota_sdk import PrivateResourceQuotaSDK
8
+ from anyscale.resource_quota.commands import (
9
+ _CREATE_DOCSTRINGS,
10
+ _CREATE_EXAMPLE,
11
+ _DELETE_DOCSTRINGS,
12
+ _DELETE_EXAMPLE,
13
+ _DISABLE_DOCSTRINGS,
14
+ _DISABLE_EXAMPLE,
15
+ _ENABLE_DOCSTRINGS,
16
+ _ENABLE_EXAMPLE,
17
+ _LIST_DOCSTRINGS,
18
+ _LIST_EXAMPLE,
19
+ create,
20
+ delete,
21
+ disable,
22
+ enable,
23
+ list,
24
+ )
25
+ from anyscale.resource_quota.models import CreateResourceQuota, ResourceQuota
26
+
27
+
28
+ class ResourceQuotaSDK:
29
+ def __init__(
30
+ self,
31
+ *,
32
+ client: Optional[AnyscaleClientInterface] = None,
33
+ logger: Optional[BlockLogger] = None,
34
+ timer: Optional[Timer] = None,
35
+ ):
36
+ self._private_sdk = PrivateResourceQuotaSDK(
37
+ client=client, logger=logger, timer=timer
38
+ )
39
+
40
+ @sdk_docs(
41
+ doc_py_example=_CREATE_EXAMPLE, arg_docstrings=_CREATE_DOCSTRINGS,
42
+ )
43
+ def create( # noqa: F811
44
+ self, create_resource_quota: CreateResourceQuota,
45
+ ) -> ResourceQuota:
46
+ """Create a resource quota.
47
+ """
48
+ return self._private_sdk.create(create_resource_quota)
49
+
50
+ @sdk_docs(
51
+ doc_py_example=_LIST_EXAMPLE, arg_docstrings=_LIST_DOCSTRINGS,
52
+ )
53
+ def list( # noqa: F811
54
+ self,
55
+ name: Optional[str] = None,
56
+ cloud: Optional[str] = None,
57
+ creator_id: Optional[str] = None,
58
+ is_enabled: Optional[bool] = None,
59
+ max_items: int = 20,
60
+ ) -> List[ResourceQuota]:
61
+ """List resource quotas.
62
+ """
63
+ return self._private_sdk.list(
64
+ name=name,
65
+ cloud=cloud,
66
+ creator_id=creator_id,
67
+ is_enabled=is_enabled,
68
+ max_items=max_items,
69
+ )
70
+
71
+ @sdk_docs(
72
+ doc_py_example=_DELETE_EXAMPLE, arg_docstrings=_DELETE_DOCSTRINGS,
73
+ )
74
+ def delete( # noqa: F811
75
+ self, resource_quota_id: str,
76
+ ):
77
+ """Delete a resource quota.
78
+ """
79
+ return self._private_sdk.delete(resource_quota_id)
80
+
81
+ @sdk_docs(
82
+ doc_py_example=_ENABLE_EXAMPLE, arg_docstrings=_ENABLE_DOCSTRINGS,
83
+ )
84
+ def enable( # noqa: F811
85
+ self, resource_quota_id: str,
86
+ ):
87
+ """Enable a resource quota.
88
+ """
89
+ return self._private_sdk.set_status(resource_quota_id, True)
90
+
91
+ @sdk_docs(
92
+ doc_py_example=_DISABLE_EXAMPLE, arg_docstrings=_DISABLE_DOCSTRINGS,
93
+ )
94
+ def disable( # noqa: F811
95
+ self, resource_quota_id: str,
96
+ ):
97
+ """Disable a resource quota.
98
+ """
99
+ return self._private_sdk.set_status(resource_quota_id, False)