skypilot-nightly 1.0.0.dev20250602__py3-none-any.whl → 1.0.0.dev20250604__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 (138) hide show
  1. sky/__init__.py +3 -3
  2. sky/adaptors/kubernetes.py +8 -0
  3. sky/backends/backend_utils.py +1 -0
  4. sky/backends/cloud_vm_ray_backend.py +8 -4
  5. sky/{clouds/service_catalog → catalog}/__init__.py +6 -17
  6. sky/{clouds/service_catalog → catalog}/aws_catalog.py +3 -3
  7. sky/{clouds/service_catalog → catalog}/azure_catalog.py +2 -2
  8. sky/{clouds/service_catalog → catalog}/common.py +10 -8
  9. sky/{clouds/service_catalog → catalog}/cudo_catalog.py +1 -1
  10. sky/{clouds/service_catalog → catalog}/data_fetchers/analyze.py +1 -1
  11. sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_aws.py +1 -1
  12. sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_vsphere.py +1 -1
  13. sky/{clouds/service_catalog → catalog}/do_catalog.py +1 -1
  14. sky/{clouds/service_catalog → catalog}/fluidstack_catalog.py +1 -1
  15. sky/{clouds/service_catalog → catalog}/gcp_catalog.py +2 -2
  16. sky/{clouds/service_catalog → catalog}/ibm_catalog.py +1 -1
  17. sky/{clouds/service_catalog → catalog}/kubernetes_catalog.py +2 -2
  18. sky/{clouds/service_catalog → catalog}/lambda_catalog.py +1 -1
  19. sky/{clouds/service_catalog → catalog}/nebius_catalog.py +1 -1
  20. sky/{clouds/service_catalog → catalog}/oci_catalog.py +1 -1
  21. sky/{clouds/service_catalog → catalog}/paperspace_catalog.py +1 -1
  22. sky/{clouds/service_catalog → catalog}/runpod_catalog.py +1 -1
  23. sky/{clouds/service_catalog → catalog}/scp_catalog.py +1 -1
  24. sky/{clouds/service_catalog → catalog}/ssh_catalog.py +3 -3
  25. sky/{clouds/service_catalog → catalog}/vast_catalog.py +1 -1
  26. sky/{clouds/service_catalog → catalog}/vsphere_catalog.py +1 -1
  27. sky/cli.py +7 -6
  28. sky/client/cli.py +7 -6
  29. sky/client/sdk.py +3 -4
  30. sky/clouds/aws.py +41 -40
  31. sky/clouds/azure.py +31 -34
  32. sky/clouds/cloud.py +8 -8
  33. sky/clouds/cudo.py +26 -26
  34. sky/clouds/do.py +24 -24
  35. sky/clouds/fluidstack.py +27 -29
  36. sky/clouds/gcp.py +45 -48
  37. sky/clouds/ibm.py +26 -26
  38. sky/clouds/kubernetes.py +24 -12
  39. sky/clouds/lambda_cloud.py +28 -30
  40. sky/clouds/nebius.py +26 -28
  41. sky/clouds/oci.py +32 -32
  42. sky/clouds/paperspace.py +24 -26
  43. sky/clouds/runpod.py +26 -28
  44. sky/clouds/scp.py +37 -36
  45. sky/clouds/utils/gcp_utils.py +3 -2
  46. sky/clouds/vast.py +27 -27
  47. sky/clouds/vsphere.py +12 -15
  48. sky/core.py +2 -2
  49. sky/dashboard/out/404.html +1 -1
  50. sky/dashboard/out/_next/static/chunks/236-fef38aa6e5639300.js +6 -0
  51. sky/dashboard/out/_next/static/chunks/37-947904ccc5687bac.js +6 -0
  52. sky/dashboard/out/_next/static/chunks/682-2be9b0f169727f2f.js +6 -0
  53. sky/dashboard/out/_next/static/chunks/856-f1b1f7f47edde2e8.js +1 -0
  54. sky/dashboard/out/_next/static/chunks/969-d7b6fb7f602bfcb3.js +1 -0
  55. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-158b70da336d8607.js +6 -0
  56. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-62c9982dc3675725.js +6 -0
  57. sky/dashboard/out/_next/static/chunks/pages/{clusters-f37ff20f0af29aae.js → clusters-5549a350f97d7ef3.js} +1 -1
  58. sky/dashboard/out/_next/static/chunks/pages/config-35383adcb0edb5e2.js +6 -0
  59. sky/dashboard/out/_next/static/chunks/pages/infra/{[context]-342bc15bb78ab2e5.js → [context]-b68ddeed712d45b5.js} +1 -1
  60. sky/dashboard/out/_next/static/chunks/pages/{infra-7b4b8e7fa9fa0827.js → infra-13b117a831702196.js} +1 -1
  61. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-a62a3c65dc9bc57c.js +11 -0
  62. sky/dashboard/out/_next/static/chunks/pages/{jobs-78a6c5ba3e24c0cf.js → jobs-a76b2700eca236f7.js} +1 -1
  63. sky/dashboard/out/_next/static/chunks/pages/{users-89f9212b81d8897e.js → users-07b523ccb19317ad.js} +1 -1
  64. sky/dashboard/out/_next/static/chunks/pages/workspace/{new-198b6e00d7d724c5.js → new-c7516f2b4c3727c0.js} +1 -1
  65. sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-2ce792183b03c341.js → [name]-7799de9e691e35d8.js} +1 -1
  66. sky/dashboard/out/_next/static/chunks/pages/workspaces-f54921ec9eb20965.js +1 -0
  67. sky/dashboard/out/_next/static/css/63d3995d8b528eb1.css +3 -0
  68. sky/dashboard/out/_next/static/vWwfD3jOky5J5jULHp8JT/_buildManifest.js +1 -0
  69. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  70. sky/dashboard/out/clusters/[cluster].html +1 -1
  71. sky/dashboard/out/clusters.html +1 -1
  72. sky/dashboard/out/config.html +1 -1
  73. sky/dashboard/out/index.html +1 -1
  74. sky/dashboard/out/infra/[context].html +1 -1
  75. sky/dashboard/out/infra.html +1 -1
  76. sky/dashboard/out/jobs/[job].html +1 -1
  77. sky/dashboard/out/jobs.html +1 -1
  78. sky/dashboard/out/users.html +1 -1
  79. sky/dashboard/out/workspace/new.html +1 -1
  80. sky/dashboard/out/workspaces/[name].html +1 -1
  81. sky/dashboard/out/workspaces.html +1 -1
  82. sky/data/storage_utils.py +5 -2
  83. sky/execution.py +1 -2
  84. sky/global_user_state.py +2 -4
  85. sky/jobs/server/core.py +1 -1
  86. sky/jobs/utils.py +31 -1
  87. sky/optimizer.py +1 -1
  88. sky/provision/cudo/cudo_machine_type.py +1 -1
  89. sky/provision/gcp/constants.py +4 -0
  90. sky/provision/kubernetes/utils.py +35 -22
  91. sky/provision/vast/utils.py +1 -1
  92. sky/provision/vsphere/common/vim_utils.py +1 -2
  93. sky/provision/vsphere/instance.py +1 -1
  94. sky/provision/vsphere/vsphere_utils.py +7 -11
  95. sky/resources.py +33 -2
  96. sky/serve/server/core.py +1 -1
  97. sky/server/common.py +86 -53
  98. sky/server/constants.py +1 -1
  99. sky/server/requests/executor.py +4 -1
  100. sky/server/requests/payloads.py +16 -0
  101. sky/server/requests/serializers/decoders.py +1 -1
  102. sky/server/server.py +3 -3
  103. sky/skypilot_config.py +88 -37
  104. sky/usage/usage_lib.py +4 -3
  105. sky/utils/accelerator_registry.py +3 -3
  106. sky/utils/controller_utils.py +4 -14
  107. sky/utils/kubernetes/deploy_remote_cluster.py +2 -1
  108. sky/utils/schemas.py +6 -9
  109. {skypilot_nightly-1.0.0.dev20250602.dist-info → skypilot_nightly-1.0.0.dev20250604.dist-info}/METADATA +1 -1
  110. {skypilot_nightly-1.0.0.dev20250602.dist-info → skypilot_nightly-1.0.0.dev20250604.dist-info}/RECORD +127 -126
  111. sky/dashboard/out/_next/static/chunks/236-7458fda7b295f305.js +0 -6
  112. sky/dashboard/out/_next/static/chunks/37-b638675d511d58b4.js +0 -6
  113. sky/dashboard/out/_next/static/chunks/682-5c12535476a21ce3.js +0 -6
  114. sky/dashboard/out/_next/static/chunks/856-ab9627e7e8ac35e8.js +0 -1
  115. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-8f270e2c9c59fa1a.js +0 -6
  116. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-25edb867a41b6b20.js +0 -6
  117. sky/dashboard/out/_next/static/chunks/pages/config-3c6a2dabf56e8cd6.js +0 -6
  118. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-c0c1dff3cd463d9e.js +0 -11
  119. sky/dashboard/out/_next/static/chunks/pages/workspaces-17d41826537196e7.js +0 -1
  120. sky/dashboard/out/_next/static/css/2b3ee34e586949a3.css +0 -3
  121. sky/dashboard/out/_next/static/dev-ndwjPgd_uQ4dcXXiv/_buildManifest.js +0 -1
  122. /sky/{clouds/service_catalog → catalog}/config.py +0 -0
  123. /sky/{clouds/service_catalog → catalog}/constants.py +0 -0
  124. /sky/{clouds/service_catalog → catalog}/data_fetchers/__init__.py +0 -0
  125. /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_azure.py +0 -0
  126. /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_cudo.py +0 -0
  127. /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_fluidstack.py +0 -0
  128. /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_gcp.py +0 -0
  129. /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_ibm.py +0 -0
  130. /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_lambda_cloud.py +0 -0
  131. /sky/{clouds/service_catalog → catalog}/data_fetchers/fetch_vast.py +0 -0
  132. /sky/dashboard/out/_next/static/chunks/{843-786c36624d5ff61f.js → 843-a097338acb89b7d7.js} +0 -0
  133. /sky/dashboard/out/_next/static/chunks/pages/{_app-ad1edd7fe17ea796.js → _app-67925f5e6382e22f.js} +0 -0
  134. /sky/dashboard/out/_next/static/{dev-ndwjPgd_uQ4dcXXiv → vWwfD3jOky5J5jULHp8JT}/_ssgManifest.js +0 -0
  135. {skypilot_nightly-1.0.0.dev20250602.dist-info → skypilot_nightly-1.0.0.dev20250604.dist-info}/WHEEL +0 -0
  136. {skypilot_nightly-1.0.0.dev20250602.dist-info → skypilot_nightly-1.0.0.dev20250604.dist-info}/entry_points.txt +0 -0
  137. {skypilot_nightly-1.0.0.dev20250602.dist-info → skypilot_nightly-1.0.0.dev20250604.dist-info}/licenses/LICENSE +0 -0
  138. {skypilot_nightly-1.0.0.dev20250602.dist-info → skypilot_nightly-1.0.0.dev20250604.dist-info}/top_level.txt +0 -0
@@ -239,8 +239,11 @@ def override_request_env_and_config(
239
239
  client_command=request_body.entrypoint_command,
240
240
  using_remote_api_server=request_body.using_remote_api_server)
241
241
  try:
242
+ logger.debug(
243
+ f'override path: {request_body.override_skypilot_config_path}')
242
244
  with skypilot_config.override_skypilot_config(
243
- request_body.override_skypilot_config):
245
+ request_body.override_skypilot_config,
246
+ request_body.override_skypilot_config_path):
244
247
  yield
245
248
  finally:
246
249
  # We need to call the save_timeline() since atexit will not be
@@ -82,6 +82,17 @@ def get_override_skypilot_config_from_client() -> Dict[str, Any]:
82
82
  return config
83
83
 
84
84
 
85
+ def get_override_skypilot_config_path_from_client() -> Optional[str]:
86
+ """Returns the override config path from the client."""
87
+ if annotations.is_on_api_server:
88
+ return None
89
+ # Currently, we don't need to check if the client-side config
90
+ # has been overridden because we only deal with cases where
91
+ # client has a project-level config/changed config and the
92
+ # api server has a different config.
93
+ return skypilot_config.loaded_config_path_serialized()
94
+
95
+
85
96
  class RequestBody(pydantic.BaseModel):
86
97
  """The request body for the SkyPilot API."""
87
98
  env_vars: Dict[str, str] = {}
@@ -89,6 +100,7 @@ class RequestBody(pydantic.BaseModel):
89
100
  entrypoint_command: str = ''
90
101
  using_remote_api_server: bool = False
91
102
  override_skypilot_config: Optional[Dict[str, Any]] = {}
103
+ override_skypilot_config_path: Optional[str] = None
92
104
 
93
105
  # Allow extra fields in the request body, which is useful for backward
94
106
  # compatibility, i.e., we can add new fields to the request body without
@@ -108,6 +120,9 @@ class RequestBody(pydantic.BaseModel):
108
120
  data['override_skypilot_config'] = data.get(
109
121
  'override_skypilot_config',
110
122
  get_override_skypilot_config_from_client())
123
+ data['override_skypilot_config_path'] = data.get(
124
+ 'override_skypilot_config_path',
125
+ get_override_skypilot_config_path_from_client())
111
126
  super().__init__(**data)
112
127
 
113
128
  def to_kwargs(self) -> Dict[str, Any]:
@@ -122,6 +137,7 @@ class RequestBody(pydantic.BaseModel):
122
137
  kwargs.pop('entrypoint_command')
123
138
  kwargs.pop('using_remote_api_server')
124
139
  kwargs.pop('override_skypilot_config')
140
+ kwargs.pop('override_skypilot_config_path')
125
141
  return kwargs
126
142
 
127
143
  @property
@@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple
6
6
 
7
7
  from sky import jobs as managed_jobs
8
8
  from sky import models
9
- from sky.clouds.service_catalog import common
9
+ from sky.catalog import common
10
10
  from sky.data import storage
11
11
  from sky.provision.kubernetes import utils as kubernetes_utils
12
12
  from sky.serve import serve_state
sky/server/server.py CHANGED
@@ -26,6 +26,7 @@ from fastapi.middleware import cors
26
26
  import starlette.middleware.base
27
27
 
28
28
  import sky
29
+ from sky import catalog
29
30
  from sky import check as sky_check
30
31
  from sky import clouds
31
32
  from sky import core
@@ -34,7 +35,6 @@ from sky import execution
34
35
  from sky import global_user_state
35
36
  from sky import models
36
37
  from sky import sky_logging
37
- from sky.clouds import service_catalog
38
38
  from sky.data import storage_utils
39
39
  from sky.jobs.server import server as jobs_rest
40
40
  from sky.provision.kubernetes import utils as kubernetes_utils
@@ -389,7 +389,7 @@ async def list_accelerators(
389
389
  request_id=request.state.request_id,
390
390
  request_name='list_accelerators',
391
391
  request_body=list_accelerator_counts_body,
392
- func=service_catalog.list_accelerators,
392
+ func=catalog.list_accelerators,
393
393
  schedule_type=requests_lib.ScheduleType.SHORT,
394
394
  )
395
395
 
@@ -404,7 +404,7 @@ async def list_accelerator_counts(
404
404
  request_id=request.state.request_id,
405
405
  request_name='list_accelerator_counts',
406
406
  request_body=list_accelerator_counts_body,
407
- func=service_catalog.list_accelerator_counts,
407
+ func=catalog.list_accelerator_counts,
408
408
  schedule_type=requests_lib.ScheduleType.SHORT,
409
409
  )
410
410
 
sky/skypilot_config.py CHANGED
@@ -55,7 +55,7 @@ import os
55
55
  import tempfile
56
56
  import threading
57
57
  import typing
58
- from typing import Any, Dict, Iterator, List, Optional, Tuple
58
+ from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
59
59
 
60
60
  import filelock
61
61
 
@@ -163,11 +163,23 @@ def _set_loaded_config(config: config_utils.Config) -> None:
163
163
  _get_config_context().config = config
164
164
 
165
165
 
166
- def _get_loaded_config_path() -> Optional[str]:
167
- return _get_config_context().config_path
166
+ def _get_loaded_config_path() -> List[Optional[str]]:
167
+ serialized = _get_config_context().config_path
168
+ if not serialized:
169
+ return []
170
+ return json.loads(serialized)
171
+
172
+
173
+ def _set_loaded_config_path(
174
+ path: Optional[Union[str, List[Optional[str]]]]) -> None:
175
+ if not path:
176
+ _get_config_context().config_path = None
177
+ if isinstance(path, str):
178
+ path = [path]
179
+ _get_config_context().config_path = json.dumps(path)
168
180
 
169
181
 
170
- def _set_loaded_config_path(path: Optional[str]) -> None:
182
+ def _set_loaded_config_path_serialized(path: Optional[str]) -> None:
171
183
  _get_config_context().config_path = path
172
184
 
173
185
 
@@ -184,9 +196,14 @@ def get_user_config_path() -> str:
184
196
  return _GLOBAL_CONFIG_PATH
185
197
 
186
198
 
187
- def get_user_config() -> config_utils.Config:
188
- """Returns the user config."""
189
- # find the user config file
199
+ def _get_config_from_path(path: Optional[str]) -> config_utils.Config:
200
+ if path is None:
201
+ return config_utils.Config()
202
+ return parse_and_validate_config_file(path)
203
+
204
+
205
+ def _resolve_user_config_path() -> Optional[str]:
206
+ # find the user config file path, None if not resolved.
190
207
  user_config_path = _get_config_file_path(ENV_VAR_GLOBAL_CONFIG)
191
208
  if user_config_path:
192
209
  logger.debug('using user config file specified by '
@@ -203,16 +220,17 @@ def get_user_config() -> config_utils.Config:
203
220
  user_config_path = get_user_config_path()
204
221
  logger.debug(f'using default user config file: {user_config_path}')
205
222
  user_config_path = os.path.expanduser(user_config_path)
206
-
207
- # load the user config file
208
223
  if os.path.exists(user_config_path):
209
- user_config = parse_and_validate_config_file(user_config_path)
210
- else:
211
- user_config = config_utils.Config()
212
- return user_config
224
+ return user_config_path
225
+ return None
213
226
 
214
227
 
215
- def _get_project_config() -> config_utils.Config:
228
+ def get_user_config() -> config_utils.Config:
229
+ """Returns the user config."""
230
+ return _get_config_from_path(_resolve_user_config_path())
231
+
232
+
233
+ def _resolve_project_config_path() -> Optional[str]:
216
234
  # find the project config file
217
235
  project_config_path = _get_config_file_path(ENV_VAR_PROJECT_CONFIG)
218
236
  if project_config_path:
@@ -231,17 +249,17 @@ def _get_project_config() -> config_utils.Config:
231
249
  f'using default project config file: {_PROJECT_CONFIG_PATH}')
232
250
  project_config_path = _PROJECT_CONFIG_PATH
233
251
  project_config_path = os.path.expanduser(project_config_path)
234
-
235
- # load the project config file
236
252
  if os.path.exists(project_config_path):
237
- project_config = parse_and_validate_config_file(project_config_path)
238
- else:
239
- project_config = config_utils.Config()
240
- return project_config
253
+ return project_config_path
254
+ return None
241
255
 
242
256
 
243
- def get_server_config() -> config_utils.Config:
244
- """Returns the server config."""
257
+ def _get_project_config() -> config_utils.Config:
258
+ """Returns the project config."""
259
+ return _get_config_from_path(_resolve_project_config_path())
260
+
261
+
262
+ def _resolve_server_config_path() -> Optional[str]:
245
263
  # find the server config file
246
264
  server_config_path = _get_config_file_path(ENV_VAR_GLOBAL_CONFIG)
247
265
  if server_config_path:
@@ -259,13 +277,14 @@ def get_server_config() -> config_utils.Config:
259
277
  server_config_path = _GLOBAL_CONFIG_PATH
260
278
  logger.debug(f'using default server config file: {server_config_path}')
261
279
  server_config_path = os.path.expanduser(server_config_path)
262
-
263
- # load the server config file
264
280
  if os.path.exists(server_config_path):
265
- server_config = parse_and_validate_config_file(server_config_path)
266
- else:
267
- server_config = config_utils.Config()
268
- return server_config
281
+ return server_config_path
282
+ return None
283
+
284
+
285
+ def get_server_config() -> config_utils.Config:
286
+ """Returns the server config."""
287
+ return _get_config_from_path(_resolve_server_config_path())
269
288
 
270
289
 
271
290
  def get_nested(keys: Tuple[str, ...],
@@ -487,9 +506,11 @@ def _reload_config_from_internal_file(internal_config_path: str) -> None:
487
506
  def _reload_config_as_server() -> None:
488
507
  # Reset the global variables, to avoid using stale values.
489
508
  _set_loaded_config(config_utils.Config())
509
+ _set_loaded_config_path(None)
490
510
 
491
511
  overrides: List[config_utils.Config] = []
492
- server_config = get_server_config()
512
+ server_config_path = _resolve_server_config_path()
513
+ server_config = _get_config_from_path(server_config_path)
493
514
  if server_config:
494
515
  overrides.append(server_config)
495
516
 
@@ -503,17 +524,21 @@ def _reload_config_as_server() -> None:
503
524
  f'server config: \n'
504
525
  f'{common_utils.dump_yaml_str(dict(overlaid_server_config))}')
505
526
  _set_loaded_config(overlaid_server_config)
527
+ _set_loaded_config_path(server_config_path)
506
528
 
507
529
 
508
530
  def _reload_config_as_client() -> None:
509
531
  # Reset the global variables, to avoid using stale values.
510
532
  _set_loaded_config(config_utils.Config())
533
+ _set_loaded_config_path(None)
511
534
 
512
535
  overrides: List[config_utils.Config] = []
513
- user_config = get_user_config()
536
+ user_config_path = _resolve_user_config_path()
537
+ user_config = _get_config_from_path(user_config_path)
514
538
  if user_config:
515
539
  overrides.append(user_config)
516
- project_config = _get_project_config()
540
+ project_config_path = _resolve_project_config_path()
541
+ project_config = _get_config_from_path(project_config_path)
517
542
  if project_config:
518
543
  overrides.append(project_config)
519
544
 
@@ -527,14 +552,26 @@ def _reload_config_as_client() -> None:
527
552
  f'client config (before task and CLI overrides): \n'
528
553
  f'{common_utils.dump_yaml_str(dict(overlaid_client_config))}')
529
554
  _set_loaded_config(overlaid_client_config)
555
+ _set_loaded_config_path([user_config_path, project_config_path])
530
556
 
531
557
 
532
558
  def loaded_config_path() -> Optional[str]:
533
- """Returns the path to the loaded config file, or
534
- '<overridden>' if the config is overridden."""
535
- if _is_config_overridden():
536
- return '<overridden>'
537
- return _get_loaded_config_path()
559
+ """Returns the path to the loaded config file, or '<overridden>' if the
560
+ config is overridden."""
561
+ path = [p for p in set(_get_loaded_config_path()) if p is not None]
562
+ if len(path) == 0:
563
+ return '<overridden>' if _is_config_overridden() else None
564
+ if len(path) == 1:
565
+ return path[0]
566
+
567
+ header = 'overridden' if _is_config_overridden() else 'merged'
568
+ path_str = ', '.join(p for p in path if p is not None)
569
+ return f'<{header} ({path_str})>'
570
+
571
+
572
+ def loaded_config_path_serialized() -> Optional[str]:
573
+ """Returns the json serialized config path list"""
574
+ return _get_config_context().config_path
538
575
 
539
576
 
540
577
  # Load on import, synchronization is guaranteed by python interpreter.
@@ -548,7 +585,9 @@ def loaded() -> bool:
548
585
 
549
586
  @contextlib.contextmanager
550
587
  def override_skypilot_config(
551
- override_configs: Optional[Dict[str, Any]]) -> Iterator[None]:
588
+ override_configs: Optional[Dict[str, Any]],
589
+ override_config_path_serialized: Optional[str] = None
590
+ ) -> Iterator[None]:
552
591
  """Overrides the user configurations."""
553
592
  # TODO(SKY-1215): allow admin user to extend the disallowed keys or specify
554
593
  # allowed keys.
@@ -557,7 +596,13 @@ def override_skypilot_config(
557
596
  yield
558
597
  return
559
598
  original_config = _get_loaded_config()
599
+ original_config_path = loaded_config_path_serialized()
560
600
  override_configs = config_utils.Config(override_configs)
601
+ if override_config_path_serialized is None:
602
+ override_config_path = []
603
+ else:
604
+ override_config_path = json.loads(override_config_path_serialized)
605
+
561
606
  disallowed_diff_keys = []
562
607
  for key in constants.SKIPPED_CLIENT_OVERRIDE_KEYS:
563
608
  value = override_configs.pop_nested(key, default_value=None)
@@ -602,6 +647,8 @@ def override_skypilot_config(
602
647
  skip_none=False)
603
648
  _set_config_overridden(True)
604
649
  _set_loaded_config(config)
650
+ _set_loaded_config_path(_get_loaded_config_path() +
651
+ override_config_path)
605
652
  yield
606
653
  except exceptions.InvalidSkyPilotConfigError as e:
607
654
  with ux_utils.print_exception_no_traceback():
@@ -616,6 +663,7 @@ def override_skypilot_config(
616
663
  finally:
617
664
  _set_loaded_config(original_config)
618
665
  _set_config_overridden(False)
666
+ _set_loaded_config_path_serialized(original_config_path)
619
667
 
620
668
 
621
669
  @contextlib.contextmanager
@@ -628,6 +676,7 @@ def replace_skypilot_config(new_configs: config_utils.Config) -> Iterator[None]:
628
676
  sky_utils.context for more details.
629
677
  """
630
678
  original_config = _get_loaded_config()
679
+ original_config_path = loaded_config_path_serialized()
631
680
  original_env_var = os.environ.get(ENV_VAR_SKYPILOT_CONFIG)
632
681
  if new_configs != original_config:
633
682
  # Modify the global config of current process or context
@@ -642,9 +691,11 @@ def replace_skypilot_config(new_configs: config_utils.Config) -> Iterator[None]:
642
691
  # Note that this code modifies os.environ directly because it
643
692
  # will be hijacked to be context-aware if a context is active.
644
693
  os.environ[ENV_VAR_SKYPILOT_CONFIG] = temp_file.name
694
+ _set_loaded_config_path(temp_file.name)
645
695
  yield
646
696
  # Restore the original config and env var.
647
697
  _set_loaded_config(original_config)
698
+ _set_loaded_config_path_serialized(original_config_path)
648
699
  if original_env_var:
649
700
  os.environ[ENV_VAR_SKYPILOT_CONFIG] = original_env_var
650
701
  else:
sky/usage/usage_lib.py CHANGED
@@ -205,8 +205,8 @@ class UsageMessageToReport(MessageToReport):
205
205
  logger.debug('Multiple accelerators are not supported: '
206
206
  f'{resources.accelerators}.')
207
207
  self.task_accelerators = list(resources.accelerators.keys())[0]
208
- self.task_num_accelerators = resources.accelerators[
209
- self.task_accelerators]
208
+ self.task_num_accelerators = int(
209
+ resources.accelerators[self.task_accelerators])
210
210
  else:
211
211
  self.task_accelerators = None
212
212
  self.task_num_accelerators = None
@@ -245,7 +245,8 @@ class UsageMessageToReport(MessageToReport):
245
245
  logger.debug('Multiple accelerators are not supported: '
246
246
  f'{resources.accelerators}.')
247
247
  self.accelerators = list(resources.accelerators.keys())[0]
248
- self.num_accelerators = resources.accelerators[self.accelerators]
248
+ self.num_accelerators = int(
249
+ resources.accelerators[self.accelerators])
249
250
  else:
250
251
  self.accelerators = None
251
252
  self.num_accelerators = None
@@ -2,7 +2,7 @@
2
2
  import typing
3
3
  from typing import Optional
4
4
 
5
- from sky.clouds import service_catalog
5
+ from sky import catalog
6
6
  from sky.utils import rich_utils
7
7
  from sky.utils import ux_utils
8
8
 
@@ -34,7 +34,7 @@ if typing.TYPE_CHECKING:
34
34
 
35
35
  # Use a cached version of accelerators to cloud mapping, so that we don't have
36
36
  # to download and read the catalog file for every cloud locally.
37
- _accelerator_df = service_catalog.common.read_catalog('common/accelerators.csv')
37
+ _accelerator_df = catalog.common.read_catalog('common/accelerators.csv')
38
38
 
39
39
  # List of non-GPU accelerators that are supported by our backend for job queue
40
40
  # scheduling.
@@ -80,7 +80,7 @@ def canonicalize_accelerator_name(accelerator: str,
80
80
  if not names and cloud_str in ['Kubernetes', None]:
81
81
  with rich_utils.safe_status(
82
82
  ux_utils.spinner_message('Listing accelerators on Kubernetes')):
83
- searched = service_catalog.list_accelerators(
83
+ searched = catalog.list_accelerators(
84
84
  name_filter=accelerator,
85
85
  case_sensitive=False,
86
86
  clouds=cloud_str,
@@ -206,8 +206,7 @@ class Controllers(enum.Enum):
206
206
  return None
207
207
 
208
208
 
209
- def high_availability_specified(cluster_name: Optional[str],
210
- skip_warning: bool = True) -> bool:
209
+ def high_availability_specified(cluster_name: Optional[str]) -> bool:
211
210
  """Check if the controller high availability is specified in user config.
212
211
  """
213
212
  controller = Controllers.from_name(cluster_name)
@@ -215,18 +214,9 @@ def high_availability_specified(cluster_name: Optional[str],
215
214
  return False
216
215
 
217
216
  if skypilot_config.loaded():
218
- high_availability = skypilot_config.get_nested(
219
- (controller.value.controller_type, 'controller',
220
- 'high_availability'), False)
221
- if high_availability:
222
- if controller.value.controller_type != 'serve':
223
- if not skip_warning:
224
- print(f'{colorama.Fore.RED}High availability controller is'
225
- 'only supported for SkyServe controller. It cannot'
226
- f'be enabled for {controller.value.name}.'
227
- f'Skipping this flag.{colorama.Style.RESET_ALL}')
228
- else:
229
- return True
217
+ return skypilot_config.get_nested((controller.value.controller_type,
218
+ 'controller', 'high_availability'),
219
+ False)
230
220
  return False
231
221
 
232
222
 
@@ -7,6 +7,7 @@ import os
7
7
  import random
8
8
  import re
9
9
  import shlex
10
+ import shutil
10
11
  import subprocess
11
12
  import sys
12
13
  import tempfile
@@ -1356,7 +1357,7 @@ def deploy_cluster(head_node,
1356
1357
  merged_file.write(result)
1357
1358
 
1358
1359
  # Replace the kubeconfig with the merged config
1359
- os.replace(merged_config, kubeconfig_path)
1360
+ shutil.move(merged_config, kubeconfig_path)
1360
1361
 
1361
1362
  # Set the new context as the current context
1362
1363
  run_command(['kubectl', 'config', 'use-context', context_name],
sky/utils/schemas.py CHANGED
@@ -6,6 +6,7 @@ https://json-schema.org/
6
6
  import enum
7
7
  from typing import Any, Dict, List, Tuple
8
8
 
9
+ from sky.catalog import constants as service_catalog_constants
9
10
  from sky.skylet import constants
10
11
 
11
12
 
@@ -66,14 +67,10 @@ _AUTOSTOP_SCHEMA = {
66
67
 
67
68
  def _get_single_resources_schema():
68
69
  """Schema for a single resource in a resources list."""
69
- # To avoid circular imports, only import when needed.
70
- # pylint: disable=import-outside-toplevel
71
- from sky.clouds import service_catalog
72
-
73
70
  # Building the regex pattern for the infra field
74
71
  # Format: cloud[/region[/zone]] or wildcards or kubernetes context
75
72
  # Match any cloud name (case insensitive)
76
- all_clouds = list(service_catalog.ALL_CLOUDS)
73
+ all_clouds = list(service_catalog_constants.ALL_CLOUDS)
77
74
  all_clouds.remove('kubernetes')
78
75
  cloud_pattern = f'(?i:({"|".join(all_clouds)}))'
79
76
 
@@ -110,7 +107,8 @@ def _get_single_resources_schema():
110
107
  'properties': {
111
108
  'cloud': {
112
109
  'type': 'string',
113
- 'case_insensitive_enum': list(service_catalog.ALL_CLOUDS)
110
+ 'case_insensitive_enum': list(
111
+ service_catalog_constants.ALL_CLOUDS)
114
112
  },
115
113
  'region': {
116
114
  'type': 'string',
@@ -856,7 +854,6 @@ _REMOTE_IDENTITY_SCHEMA_KUBERNETES = {
856
854
 
857
855
  def get_config_schema():
858
856
  # pylint: disable=import-outside-toplevel
859
- from sky.clouds import service_catalog
860
857
  from sky.utils import kubernetes_enums
861
858
 
862
859
  resources_schema = {
@@ -1165,7 +1162,7 @@ def get_config_schema():
1165
1162
  'items': {
1166
1163
  'type': 'string',
1167
1164
  'case_insensitive_enum':
1168
- (list(service_catalog.ALL_CLOUDS) + ['cloudflare'])
1165
+ (list(service_catalog_constants.ALL_CLOUDS) + ['cloudflare'])
1169
1166
  }
1170
1167
  }
1171
1168
 
@@ -1213,7 +1210,7 @@ def get_config_schema():
1213
1210
  workspace_schema = {'type': 'string'}
1214
1211
 
1215
1212
  allowed_workspace_cloud_names = list(
1216
- service_catalog.ALL_CLOUDS) + ['cloudflare']
1213
+ service_catalog_constants.ALL_CLOUDS) + ['cloudflare']
1217
1214
  # Create pattern for not supported clouds, i.e.
1218
1215
  # all clouds except gcp, kubernetes, ssh
1219
1216
  not_supported_clouds = [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20250602
3
+ Version: 1.0.0.dev20250604
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0