anyscale 0.26.52__py3-none-any.whl → 0.26.54__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/anyscale_client.py +26 -26
- anyscale/_private/anyscale_client/common.py +5 -5
- anyscale/_private/anyscale_client/fake_anyscale_client.py +6 -6
- anyscale/_private/docgen/__main__.py +8 -8
- anyscale/_private/docgen/generator.py +48 -10
- anyscale/_private/docgen/models.md +2 -2
- anyscale/_private/sdk/__init__.py +124 -1
- anyscale/_private/workload/workload_config.py +4 -6
- anyscale/_private/workload/workload_sdk.py +9 -11
- anyscale/client/README.md +14 -13
- anyscale/client/openapi_client/__init__.py +4 -4
- anyscale/client/openapi_client/api/default_api.py +395 -325
- anyscale/client/openapi_client/models/__init__.py +4 -4
- anyscale/client/openapi_client/models/aws_config.py +2 -2
- anyscale/client/openapi_client/models/baseimagesenum.py +76 -1
- anyscale/client/openapi_client/models/cloud_data_bucket_file_type.py +2 -1
- anyscale/client/openapi_client/models/cloud_data_bucket_presigned_url_request.py +31 -3
- anyscale/client/openapi_client/models/cloud_deployment.py +37 -36
- anyscale/client/openapi_client/models/create_resource_notification.py +31 -3
- anyscale/client/openapi_client/models/{decorated_cloud_deployment.py → decorated_cloud_resource.py} +124 -96
- anyscale/client/openapi_client/models/{clouddeployment_list_response.py → decoratedcloudresource_list_response.py} +15 -15
- anyscale/client/openapi_client/models/{clouddeployment_response.py → decoratedcloudresource_response.py} +11 -11
- anyscale/client/openapi_client/models/file_storage.py +4 -4
- anyscale/client/openapi_client/models/gcp_config.py +2 -2
- anyscale/client/openapi_client/models/ha_job_error_types.py +9 -2
- anyscale/client/openapi_client/models/object_storage.py +2 -2
- anyscale/client/openapi_client/models/{decoratedclouddeployment_response.py → presigned_url_response.py} +24 -22
- anyscale/client/openapi_client/models/production_job_event.py +31 -3
- anyscale/client/openapi_client/models/resource_alert_event_type.py +2 -1
- anyscale/client/openapi_client/models/resource_notification.py +29 -1
- anyscale/client/openapi_client/models/supportedbaseimagesenum.py +76 -1
- anyscale/client/openapi_client/models/workload_info.py +31 -3
- anyscale/client/openapi_client/models/workload_state_info.py +29 -1
- anyscale/cloud/models.py +39 -42
- anyscale/commands/cloud_commands.py +25 -23
- anyscale/commands/command_examples.py +10 -10
- anyscale/commands/exec_commands.py +12 -1
- anyscale/commands/list_commands.py +42 -12
- anyscale/commands/project_commands.py +23 -10
- anyscale/commands/schedule_commands.py +22 -11
- anyscale/commands/service_commands.py +11 -6
- anyscale/commands/util.py +94 -1
- anyscale/commands/workspace_commands.py +92 -38
- anyscale/compute_config/__init__.py +1 -1
- anyscale/compute_config/_private/compute_config_sdk.py +8 -11
- anyscale/compute_config/commands.py +3 -3
- anyscale/compute_config/models.py +30 -30
- anyscale/controllers/cloud_controller.py +306 -300
- anyscale/controllers/kubernetes_verifier.py +1 -1
- anyscale/job/_private/job_sdk.py +12 -12
- anyscale/job/models.py +1 -1
- anyscale/sdk/anyscale_client/models/baseimagesenum.py +76 -1
- anyscale/sdk/anyscale_client/models/supportedbaseimagesenum.py +76 -1
- anyscale/shared_anyscale_utils/latest_ray_version.py +1 -1
- anyscale/version.py +1 -1
- anyscale/workspace/commands.py +114 -23
- anyscale/workspace/models.py +3 -5
- {anyscale-0.26.52.dist-info → anyscale-0.26.54.dist-info}/METADATA +1 -1
- {anyscale-0.26.52.dist-info → anyscale-0.26.54.dist-info}/RECORD +64 -64
- {anyscale-0.26.52.dist-info → anyscale-0.26.54.dist-info}/WHEEL +0 -0
- {anyscale-0.26.52.dist-info → anyscale-0.26.54.dist-info}/entry_points.txt +0 -0
- {anyscale-0.26.52.dist-info → anyscale-0.26.54.dist-info}/licenses/LICENSE +0 -0
- {anyscale-0.26.52.dist-info → anyscale-0.26.54.dist-info}/licenses/NOTICE +0 -0
- {anyscale-0.26.52.dist-info → anyscale-0.26.54.dist-info}/top_level.txt +0 -0
@@ -1292,7 +1292,7 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
1292
1292
|
def _upload_local_runtime_env(
|
1293
1293
|
self,
|
1294
1294
|
cloud_id: str,
|
1295
|
-
|
1295
|
+
cloud_resource_id: Optional[str],
|
1296
1296
|
zip_file_bytes: bytes,
|
1297
1297
|
content_hash: str,
|
1298
1298
|
overwrite_existing_file: bool,
|
@@ -1302,7 +1302,7 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
1302
1302
|
file_type=CloudDataBucketFileType.RUNTIME_ENV_PACKAGES,
|
1303
1303
|
file_name=file_name,
|
1304
1304
|
access_mode=CloudDataBucketAccessMode.WRITE,
|
1305
|
-
|
1305
|
+
cloud_resource_id=cloud_resource_id,
|
1306
1306
|
)
|
1307
1307
|
info: CloudDataBucketPresignedUrlResponse = self._internal_api_client.generate_cloud_data_bucket_presigned_url_api_v2_clouds_cloud_id_generate_cloud_data_bucket_presigned_url_post(
|
1308
1308
|
cloud_id, request
|
@@ -1355,27 +1355,27 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
1355
1355
|
cloud_id: str,
|
1356
1356
|
excludes: Optional[List[str]] = None,
|
1357
1357
|
overwrite_existing_file: bool = OVERWRITE_EXISTING_CLOUD_STORAGE_FILES,
|
1358
|
-
|
1358
|
+
cloud_resource_name: Optional[str] = None,
|
1359
1359
|
) -> str:
|
1360
1360
|
if not pathlib.Path(local_dir).is_dir():
|
1361
1361
|
raise RuntimeError(f"Path '{local_dir}' is not a valid directory.")
|
1362
1362
|
|
1363
|
-
|
1364
|
-
if
|
1365
|
-
|
1363
|
+
cloud_resource_id = None
|
1364
|
+
if cloud_resource_name is not None:
|
1365
|
+
cloud_resources = self._internal_api_client.get_cloud_resources_api_v2_clouds_cloud_id_resources_get(
|
1366
1366
|
cloud_id=cloud_id,
|
1367
1367
|
).results
|
1368
|
-
|
1368
|
+
cloud_resource_id = next(
|
1369
1369
|
(
|
1370
|
-
|
1371
|
-
for
|
1372
|
-
if
|
1370
|
+
cloud_resource.cloud_resource_id
|
1371
|
+
for cloud_resource in cloud_resources
|
1372
|
+
if cloud_resource.name == cloud_resource_name
|
1373
1373
|
),
|
1374
1374
|
None,
|
1375
1375
|
)
|
1376
|
-
if
|
1376
|
+
if cloud_resource_id is None:
|
1377
1377
|
raise ValueError(
|
1378
|
-
f"Cloud
|
1378
|
+
f"Cloud resource '{cloud_resource_name}' not found in cloud '{cloud_id}'"
|
1379
1379
|
)
|
1380
1380
|
|
1381
1381
|
with zip_local_dir(local_dir, excludes=excludes) as (
|
@@ -1385,31 +1385,31 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
1385
1385
|
):
|
1386
1386
|
info = self._upload_local_runtime_env(
|
1387
1387
|
cloud_id=cloud_id,
|
1388
|
-
|
1388
|
+
cloud_resource_id=cloud_resource_id,
|
1389
1389
|
zip_file_bytes=zip_file_bytes,
|
1390
1390
|
content_hash=content_hash,
|
1391
1391
|
overwrite_existing_file=overwrite_existing_file,
|
1392
1392
|
)
|
1393
1393
|
return info.file_uri
|
1394
1394
|
|
1395
|
-
def
|
1395
|
+
def upload_local_dir_to_cloud_storage_multi_cloud_resource(
|
1396
1396
|
self,
|
1397
1397
|
local_dir: str,
|
1398
1398
|
*,
|
1399
1399
|
cloud_id: str,
|
1400
|
-
|
1400
|
+
cloud_resource_names: List[Optional[str]],
|
1401
1401
|
excludes: Optional[List[str]] = None,
|
1402
1402
|
overwrite_existing_file: bool = False,
|
1403
1403
|
) -> str:
|
1404
1404
|
if not pathlib.Path(local_dir).is_dir():
|
1405
1405
|
raise RuntimeError(f"Path '{local_dir}' is not a valid directory.")
|
1406
1406
|
|
1407
|
-
|
1407
|
+
all_cloud_resources = self._internal_api_client.get_cloud_resources_api_v2_clouds_cloud_id_resources_get(
|
1408
1408
|
cloud_id=cloud_id,
|
1409
1409
|
).results
|
1410
|
-
|
1411
|
-
|
1412
|
-
for
|
1410
|
+
cloud_resource_names_to_ids = {
|
1411
|
+
cloud_resource.name: cloud_resource.cloud_resource_id
|
1412
|
+
for cloud_resource in all_cloud_resources
|
1413
1413
|
}
|
1414
1414
|
|
1415
1415
|
bucket_paths = set()
|
@@ -1419,19 +1419,19 @@ class AnyscaleClient(AnyscaleClientInterface):
|
|
1419
1419
|
zip_file_bytes,
|
1420
1420
|
content_hash,
|
1421
1421
|
):
|
1422
|
-
for
|
1423
|
-
if
|
1424
|
-
if
|
1422
|
+
for cloud_resource_name in cloud_resource_names:
|
1423
|
+
if cloud_resource_name is not None:
|
1424
|
+
if cloud_resource_name not in cloud_resource_names_to_ids:
|
1425
1425
|
raise ValueError(
|
1426
|
-
f"Cloud
|
1426
|
+
f"Cloud resource '{cloud_resource_name}' not found in cloud '{cloud_id}'"
|
1427
1427
|
)
|
1428
|
-
|
1428
|
+
cloud_resource_id = cloud_resource_names_to_ids[cloud_resource_name]
|
1429
1429
|
else:
|
1430
|
-
|
1430
|
+
cloud_resource_id = None
|
1431
1431
|
|
1432
1432
|
info = self._upload_local_runtime_env(
|
1433
1433
|
cloud_id=cloud_id,
|
1434
|
-
|
1434
|
+
cloud_resource_id=cloud_resource_id,
|
1435
1435
|
zip_file_bytes=zip_file_bytes,
|
1436
1436
|
content_hash=content_hash,
|
1437
1437
|
overwrite_existing_file=overwrite_existing_file,
|
@@ -57,7 +57,7 @@ from anyscale.utils.workspace_notification import WorkspaceNotification
|
|
57
57
|
# Maybe just make it part of the release process to update it, or fetch the
|
58
58
|
# default builds and get the latest one. The best thing to do is probably
|
59
59
|
# to populate this in the backend.
|
60
|
-
DEFAULT_RAY_VERSION = "2.49.
|
60
|
+
DEFAULT_RAY_VERSION = "2.49.1" # RAY_RELEASE_UPDATE: update to latest version.
|
61
61
|
DEFAULT_PYTHON_VERSION = "py311"
|
62
62
|
RUNTIME_ENV_PACKAGE_FORMAT = "pkg_{content_hash}.zip"
|
63
63
|
|
@@ -520,7 +520,7 @@ class AnyscaleClientInterface(ABC):
|
|
520
520
|
cloud_id: str,
|
521
521
|
excludes: Optional[List[str]] = None,
|
522
522
|
overwrite_existing_file: bool = False,
|
523
|
-
|
523
|
+
cloud_resource_name: Optional[str] = None,
|
524
524
|
) -> str:
|
525
525
|
"""Upload the provided directory to cloud storage and return a URI for it.
|
526
526
|
|
@@ -535,17 +535,17 @@ class AnyscaleClientInterface(ABC):
|
|
535
535
|
raise NotImplementedError
|
536
536
|
|
537
537
|
@abstractmethod
|
538
|
-
def
|
538
|
+
def upload_local_dir_to_cloud_storage_multi_cloud_resource(
|
539
539
|
self,
|
540
540
|
local_dir: str,
|
541
541
|
*,
|
542
542
|
cloud_id: str,
|
543
|
-
|
543
|
+
cloud_resource_names: List[Optional[str]],
|
544
544
|
excludes: Optional[List[str]] = None,
|
545
545
|
overwrite_existing_file: bool = False,
|
546
546
|
) -> str:
|
547
547
|
"""Upload the provided directory to the object storage for each of the provided
|
548
|
-
cloud
|
548
|
+
cloud resources and return the bucket path of the uploaded file.
|
549
549
|
|
550
550
|
The directory will be zipped and the resulting bucket path will later be converted
|
551
551
|
to a URI that can be used in a Ray runtime_env.
|
@@ -1019,12 +1019,12 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
1019
1019
|
cloud_id: str,
|
1020
1020
|
excludes: Optional[List[str]] = None, # noqa: ARG002
|
1021
1021
|
overwrite_existing_file: bool = False, # noqa: ARG002
|
1022
|
-
|
1022
|
+
cloud_resource_name: Optional[str] = None,
|
1023
1023
|
) -> str:
|
1024
1024
|
# Ensure that URIs are consistent for the same passed directory.
|
1025
1025
|
bucket = self.CLOUD_BUCKET.format(cloud_id=cloud_id)
|
1026
|
-
if
|
1027
|
-
bucket += f"_{
|
1026
|
+
if cloud_resource_name is not None:
|
1027
|
+
bucket += f"_{cloud_resource_name}"
|
1028
1028
|
if local_dir not in self._upload_uri_mapping:
|
1029
1029
|
self._upload_uri_mapping[
|
1030
1030
|
local_dir
|
@@ -1032,19 +1032,19 @@ class FakeAnyscaleClient(AnyscaleClientInterface):
|
|
1032
1032
|
|
1033
1033
|
return self._upload_uri_mapping[local_dir]
|
1034
1034
|
|
1035
|
-
def
|
1035
|
+
def upload_local_dir_to_cloud_storage_multi_cloud_resource(
|
1036
1036
|
self,
|
1037
1037
|
local_dir: str,
|
1038
1038
|
*,
|
1039
1039
|
cloud_id: str,
|
1040
|
-
|
1040
|
+
cloud_resource_names: List[Optional[str]],
|
1041
1041
|
excludes: Optional[List[str]] = None, # noqa: ARG002
|
1042
1042
|
overwrite_existing_file: bool = False, # noqa: ARG002
|
1043
1043
|
) -> str:
|
1044
1044
|
bucket = self.CLOUD_BUCKET.format(cloud_id=cloud_id)
|
1045
1045
|
if local_dir not in self._upload_bucket_path_mapping:
|
1046
1046
|
self._upload_bucket_path_mapping[local_dir] = (
|
1047
|
-
|
1047
|
+
cloud_resource_names,
|
1048
1048
|
f"{bucket}/fake_pkg_{str(uuid.uuid4())}.zip",
|
1049
1049
|
)
|
1050
1050
|
return self._upload_bucket_path_mapping[local_dir][1]
|
@@ -13,9 +13,9 @@ from anyscale.aggregated_instance_usage.models import DownloadCSVFilters
|
|
13
13
|
from anyscale.cloud.models import (
|
14
14
|
AWSConfig,
|
15
15
|
Cloud,
|
16
|
-
CloudDeployment,
|
17
16
|
CloudPermissionLevel,
|
18
17
|
CloudProvider,
|
18
|
+
CloudResource,
|
19
19
|
ComputeStack,
|
20
20
|
CreateCloudCollaborator,
|
21
21
|
FileStorage,
|
@@ -53,7 +53,7 @@ from anyscale.compute_config.models import (
|
|
53
53
|
ComputeConfigVersion,
|
54
54
|
HeadNodeConfig,
|
55
55
|
MarketType,
|
56
|
-
|
56
|
+
MultiResourceComputeConfig,
|
57
57
|
WorkerNodeGroupConfig,
|
58
58
|
)
|
59
59
|
from anyscale.image.models import ImageBuild, ImageBuildStatus
|
@@ -330,7 +330,7 @@ ALL_MODULES = [
|
|
330
330
|
],
|
331
331
|
models=[
|
332
332
|
ComputeConfig,
|
333
|
-
|
333
|
+
MultiResourceComputeConfig,
|
334
334
|
HeadNodeConfig,
|
335
335
|
WorkerNodeGroupConfig,
|
336
336
|
MarketType,
|
@@ -448,8 +448,8 @@ ALL_MODULES = [
|
|
448
448
|
cloud_commands.cloud_delete,
|
449
449
|
cloud_commands.cloud_verify,
|
450
450
|
cloud_commands.list_cloud,
|
451
|
-
cloud_commands.
|
452
|
-
cloud_commands.
|
451
|
+
cloud_commands.cloud_resource_create,
|
452
|
+
cloud_commands.cloud_resource_delete,
|
453
453
|
cloud_commands.cloud_config_get,
|
454
454
|
cloud_commands.cloud_config_update,
|
455
455
|
cloud_commands.cloud_set_default,
|
@@ -469,7 +469,7 @@ ALL_MODULES = [
|
|
469
469
|
Cloud,
|
470
470
|
CloudPermissionLevel,
|
471
471
|
CreateCloudCollaborator,
|
472
|
-
|
472
|
+
CloudResource,
|
473
473
|
ComputeStack,
|
474
474
|
CloudProvider,
|
475
475
|
NetworkingMode,
|
@@ -481,8 +481,8 @@ ALL_MODULES = [
|
|
481
481
|
KubernetesConfig,
|
482
482
|
],
|
483
483
|
cli_command_group_prefix={
|
484
|
-
cloud_commands.
|
485
|
-
cloud_commands.
|
484
|
+
cloud_commands.cloud_resource_create: "resource",
|
485
|
+
cloud_commands.cloud_resource_delete: "resource",
|
486
486
|
cloud_commands.cloud_config_get: "config",
|
487
487
|
cloud_commands.cloud_config_update: "config",
|
488
488
|
},
|
@@ -20,7 +20,11 @@ from anyscale._private.models.model_base import (
|
|
20
20
|
ModelEnumType,
|
21
21
|
ResultIterator,
|
22
22
|
)
|
23
|
-
from anyscale.commands.util import
|
23
|
+
from anyscale.commands.util import (
|
24
|
+
AnyscaleCommand,
|
25
|
+
DeprecatedAnyscaleCommand,
|
26
|
+
LegacyAnyscaleCommand,
|
27
|
+
)
|
24
28
|
|
25
29
|
|
26
30
|
ModelType = Union[ModelBaseType, ModelEnumType]
|
@@ -301,13 +305,20 @@ class MarkdownGenerator:
|
|
301
305
|
raise ValueError(
|
302
306
|
f"Config model '{t.__name__}' is missing a '__doc_yaml_example__'."
|
303
307
|
)
|
304
|
-
if
|
308
|
+
if (
|
309
|
+
isinstance(
|
310
|
+
t, (AnyscaleCommand, DeprecatedAnyscaleCommand, LegacyAnyscaleCommand)
|
311
|
+
)
|
312
|
+
and not cli_example
|
313
|
+
):
|
305
314
|
raise ValueError(
|
306
315
|
f"CLI command '{t.name}' is missing a '__doc_cli_example__'."
|
307
316
|
)
|
308
317
|
if (
|
309
318
|
not isinstance(t, ModelBaseType)
|
310
|
-
and not isinstance(
|
319
|
+
and not isinstance(
|
320
|
+
t, (AnyscaleCommand, DeprecatedAnyscaleCommand, LegacyAnyscaleCommand)
|
321
|
+
)
|
311
322
|
and not py_example
|
312
323
|
):
|
313
324
|
raise ValueError(
|
@@ -321,8 +332,10 @@ class MarkdownGenerator:
|
|
321
332
|
try:
|
322
333
|
yaml.safe_load(yaml_example)
|
323
334
|
except Exception as e: # noqa: BLE001
|
335
|
+
# For CLI commands, use t.name; for SDK functions/models, use t.__name__
|
336
|
+
name = getattr(t, "name", getattr(t, "__name__", str(t)))
|
324
337
|
raise ValueError(
|
325
|
-
f"'{
|
338
|
+
f"'{name}.__doc_yaml_example__' is not valid YAML syntax"
|
326
339
|
) from e
|
327
340
|
|
328
341
|
yaml_example = yaml_example.strip("\n")
|
@@ -334,8 +347,10 @@ class MarkdownGenerator:
|
|
334
347
|
try:
|
335
348
|
ast.parse(py_example)
|
336
349
|
except Exception as e: # noqa: BLE001
|
350
|
+
# For CLI commands, use t.name; for SDK functions/models, use t.__name__
|
351
|
+
name = getattr(t, "name", getattr(t, "__name__", str(t)))
|
337
352
|
raise ValueError(
|
338
|
-
f"'{
|
353
|
+
f"'{name}.__doc_py_example__' is not valid Python syntax"
|
339
354
|
) from e
|
340
355
|
|
341
356
|
py_example = py_example.strip("\n")
|
@@ -413,7 +428,7 @@ class MarkdownGenerator:
|
|
413
428
|
|
414
429
|
return md
|
415
430
|
|
416
|
-
def _gen_markdown_for_cli_command(
|
431
|
+
def _gen_markdown_for_cli_command( # noqa: PLR0912
|
417
432
|
self, c: click.Command, *, cli_prefix: str
|
418
433
|
) -> str:
|
419
434
|
"""Generate a markdown section for a CLI command.
|
@@ -438,9 +453,31 @@ class MarkdownGenerator:
|
|
438
453
|
else:
|
439
454
|
new_c = c.get_new_cli()
|
440
455
|
new_cli_prefix = c.get_new_prefix()
|
441
|
-
|
442
|
-
|
443
|
-
|
456
|
+
if new_c and new_cli_prefix:
|
457
|
+
md += ":::warning\n"
|
458
|
+
md += f"This command is deprecated. Upgrade to [{new_cli_prefix} {new_c.name}]({self._get_cli_anchor(new_c, new_cli_prefix)}). \n"
|
459
|
+
md += ":::\n"
|
460
|
+
elif isinstance(c, DeprecatedAnyscaleCommand):
|
461
|
+
md = f'### `{cli_prefix} {c.name}` <span class="label-h3 label-deprecated">Deprecated</span>\n'
|
462
|
+
md += ":::warning[Deprecated]\n"
|
463
|
+
# Build deprecation message similar to the command itself
|
464
|
+
parts = []
|
465
|
+
if hasattr(c, "__deprecation_message__") and c.__deprecation_message__:
|
466
|
+
parts.append(c.__deprecation_message__)
|
467
|
+
else:
|
468
|
+
parts.append(f"Command '{c.name}' is deprecated")
|
469
|
+
|
470
|
+
if hasattr(c, "__removal_date__") and c.__removal_date__:
|
471
|
+
date_str = c._format_removal_date(c.__removal_date__) # noqa: SLF001
|
472
|
+
if date_str:
|
473
|
+
parts.append(f"and will be removed on {date_str}")
|
474
|
+
|
475
|
+
if hasattr(c, "__alternative__") and c.__alternative__:
|
476
|
+
parts.append(f"Please {c.__alternative__}")
|
477
|
+
|
478
|
+
deprecation_msg = ". ".join(parts) + "."
|
479
|
+
md += deprecation_msg + "\n"
|
480
|
+
md += ":::\n"
|
444
481
|
elif isinstance(c, AnyscaleCommand) and c.is_alpha:
|
445
482
|
md = f'### `{cli_prefix} {c.name}` <span class="label-h3 label-alpha">Alpha</span>\n'
|
446
483
|
md += ":::warning\n"
|
@@ -478,7 +515,8 @@ class MarkdownGenerator:
|
|
478
515
|
md += "\n"
|
479
516
|
|
480
517
|
should_have_example = not (
|
481
|
-
isinstance(c, LegacyAnyscaleCommand)
|
518
|
+
isinstance(c, (LegacyAnyscaleCommand, DeprecatedAnyscaleCommand))
|
519
|
+
or cli_prefix in CLI_NO_EXAMPLES
|
482
520
|
)
|
483
521
|
has_cli_example = hasattr(c, "__doc_cli_example__")
|
484
522
|
if should_have_example or has_cli_example:
|