diff --git a/src/dstack/_internal/core/models/envs.py b/src/dstack/_internal/core/models/envs.py index 268e39118..03e7b6031 100644 --- a/src/dstack/_internal/core/models/envs.py +++ b/src/dstack/_internal/core/models/envs.py @@ -102,10 +102,11 @@ def __setitem__(self, item, value): def copy(self, **kwargs) -> Self: # Env.copy() is tricky because it copies only the hidden top-level {"__root__": {...}} # structure, not the actual nested dict representing the env itself. - # To avoid possible bugs, we prohibit shallow copying altogether. + # So we copy __root__ explicitly in case of a shallow copy. + new_copy = super().copy(**kwargs) if not kwargs.get("deep", False): - raise TypeError(f"shallow copying of {self.__class__.__name__} is prohibited") - return super().copy(**kwargs) + new_copy.__root__ = new_copy.__root__.copy() + return new_copy def as_dict(self) -> Dict[str, str]: """ diff --git a/src/dstack/_internal/core/models/profiles.py b/src/dstack/_internal/core/models/profiles.py index 2b01ddc45..89767a240 100644 --- a/src/dstack/_internal/core/models/profiles.py +++ b/src/dstack/_internal/core/models/profiles.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import List, Optional, Union, overload +from typing import Any, Dict, List, Optional, Union, overload from pydantic import Field, root_validator, validator from typing_extensions import Annotated, Literal @@ -241,6 +241,22 @@ class ProfileParams(CoreModel): Field(description="Run termination policy based on utilization"), ] = None + # # Deprecated and unused. Left for compatibility with 0.18 clients. + pool_name: Annotated[Optional[str], Field(exclude=True)] = None + instance_name: Annotated[Optional[str], Field(exclude=True)] = None + retry_policy: Annotated[Optional[ProfileRetryPolicy], Field(exclude=True)] = None + termination_policy: Annotated[Optional[TerminationPolicy], Field(exclude=True)] = None + termination_idle_time: Annotated[Optional[Union[str, int]], Field(exclude=True)] = None + + class Config: + @staticmethod + def schema_extra(schema: Dict[str, Any]) -> None: + del schema["properties"]["pool_name"] + del schema["properties"]["instance_name"] + del schema["properties"]["retry_policy"] + del schema["properties"]["termination_policy"] + del schema["properties"]["termination_idle_time"] + _validate_max_duration = validator("max_duration", pre=True, allow_reuse=True)( parse_max_duration ) diff --git a/src/dstack/_internal/server/schemas/gateways.py b/src/dstack/_internal/server/schemas/gateways.py index b94fcbb23..2ffc89143 100644 --- a/src/dstack/_internal/server/schemas/gateways.py +++ b/src/dstack/_internal/server/schemas/gateways.py @@ -1,11 +1,25 @@ -from typing import List +from typing import Annotated, Any, Dict, List, Optional +from pydantic import Field + +from dstack._internal.core.models.backends.base import BackendType from dstack._internal.core.models.common import CoreModel from dstack._internal.core.models.gateways import GatewayConfiguration class CreateGatewayRequest(CoreModel): configuration: GatewayConfiguration + # Deprecated and unused. Left for compatibility with 0.18 clients. + name: Annotated[Optional[str], Field(exclude=True)] = None + backend_type: Annotated[Optional[BackendType], Field(exclude=True)] = None + region: Annotated[Optional[str], Field(exclude=True)] = None + + class Config: + @staticmethod + def schema_extra(schema: Dict[str, Any]) -> None: + del schema["properties"]["name"] + del schema["properties"]["backend_type"] + del schema["properties"]["region"] class GetGatewayRequest(CoreModel):