content: #  Copyright (c) ZenML GmbH 2022. All Rights Reserved.
  #
  #  Licensed under the Apache License, Version 2.0 (the "License");
  #  you may not use this file except in compliance with the License.
  #  You may obtain a copy of the License at:
  #
  #       https://www.apache.org/licenses/LICENSE-2.0
  #
  #  Unless required by applicable law or agreed to in writing, software
  #  distributed under the License is distributed on an "AS IS" BASIS,
  #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  #  or implied. See the License for the specific language governing
  #  permissions and limitations under the License.
  """ZenML Store interface."""
  
  import datetime
  from abc import ABC, abstractmethod
  from typing import List, Optional, Tuple, Union
  from uuid import UUID
  
  from zenml.config.pipeline_run_configuration import PipelineRunConfiguration
  from zenml.enums import StackDeploymentProvider
  from zenml.models import (
      ActionFilter,
      ActionRequest,
      ActionResponse,
      ActionUpdate,
      APIKeyFilter,
      APIKeyRequest,
      APIKeyResponse,
      APIKeyRotateRequest,
      APIKeyUpdate,
      ArtifactFilter,
      ArtifactRequest,
      ArtifactResponse,
      ArtifactUpdate,
      ArtifactVersionFilter,
      ArtifactVersionRequest,
      ArtifactVersionResponse,
      ArtifactVersionUpdate,
      ArtifactVisualizationResponse,
      CodeReferenceResponse,
      CodeRepositoryFilter,
      CodeRepositoryRequest,
      CodeRepositoryResponse,
      CodeRepositoryUpdate,
      ComponentFilter,
      ComponentRequest,
      ComponentResponse,
      ComponentUpdate,
      CuratedVisualizationRequest,
      CuratedVisualizationResponse,
      CuratedVisualizationUpdate,
      DeployedStack,
      DeploymentFilter,
      DeploymentRequest,
      DeploymentResponse,
      DeploymentUpdate,
      EventSourceFilter,
      EventSourceRequest,
      EventSourceResponse,
      EventSourceUpdate,
      FlavorFilter,
      FlavorRequest,
      FlavorResponse,
      FlavorUpdate,
      LogsResponse,
      ModelFilter,
      ModelRequest,
      ModelResponse,
      ModelUpdate,
      ModelVersionArtifactFilter,
      ModelVersionArtifactRequest,
      ModelVersionArtifactResponse,
      ModelVersionFilter,
      ModelVersionPipelineRunFilter,
      ModelVersionPipelineRunRequest,
      ModelVersionPipelineRunResponse,
      ModelVersionRequest,
      ModelVersionResponse,
      ModelVersionUpdate,
      OAuthDeviceFilter,
      OAuthDeviceResponse,
      OAuthDeviceUpdate,
      Page,
      PipelineBuildFilter,
      PipelineBuildRequest,
      PipelineBuildResponse,
      PipelineFilter,
      PipelineRequest,
      PipelineResponse,
      PipelineRunFilter,
      PipelineRunRequest,
      PipelineRunResponse,
      PipelineRunUpdate,
      PipelineSnapshotFilter,
      PipelineSnapshotRequest,
      PipelineSnapshotResponse,
      PipelineSnapshotRunRequest,
      PipelineSnapshotUpdate,
      PipelineUpdate,
      ProjectFilter,
      ProjectRequest,
      ProjectResponse,
      ProjectUpdate,
      RunMetadataRequest,
      RunTemplateFilter,
      RunTemplateRequest,
      RunTemplateResponse,
      RunTemplateUpdate,
      ScheduleFilter,
      ScheduleRequest,
      ScheduleResponse,
      ScheduleUpdate,
      SecretFilter,
      SecretRequest,
      SecretResponse,
      SecretUpdate,
      ServerModel,
      ServerSettingsResponse,
      ServerSettingsUpdate,
      ServiceAccountFilter,
      ServiceAccountRequest,
      ServiceAccountResponse,
      ServiceAccountUpdate,
      ServiceConnectorFilter,
      ServiceConnectorRequest,
      ServiceConnectorResourcesModel,
      ServiceConnectorResponse,
      ServiceConnectorTypeModel,
      ServiceConnectorUpdate,
      ServiceFilter,
      ServiceRequest,
      ServiceResponse,
      ServiceUpdate,
      StackDeploymentConfig,
      StackDeploymentInfo,
      StackFilter,
      StackRequest,
      StackResponse,
      StackUpdate,
      StepHeartbeatResponse,
      StepRunFilter,
      StepRunRequest,
      StepRunResponse,
      StepRunUpdate,
      TagFilter,
      TagRequest,
      TagResourceRequest,
      TagResourceResponse,
      TagResponse,
      TagUpdate,
      TriggerExecutionFilter,
      TriggerExecutionResponse,
      TriggerFilter,
      TriggerRequest,
      TriggerResponse,
      TriggerUpdate,
      UserFilter,
      UserRequest,
      UserResponse,
      UserUpdate,
  )
  
  
  class ZenStoreInterface(ABC):
      """ZenML store interface.
  
      All ZenML stores must implement the methods in this interface.
  
      The methods in this interface are organized in the following way:
  
       * they are grouped into categories based on the type of resource
         that they operate on (e.g. stacks, stack components, etc.)
  
       * each category has a set of CRUD methods (create, read, update, delete)
         that operate on the resources in that category. The order of the methods
         in each category should be:
  
         * create methods - store a new resource. These methods
           should fill in generated fields (e.g. UUIDs, creation timestamps) in
           the resource and return the updated resource.
         * get methods - retrieve a single existing resource identified by a
           unique key or identifier from the store. These methods should always
           return a resource and raise an exception if the resource does not
           exist.
         * list methods - retrieve a list of resources from the store. These
           methods should accept a set of filter parameters that can be used to
           filter the list of resources retrieved from the store.
         * update methods - update an existing resource in the store. These
           methods should expect the updated resource to be correctly identified
           by its unique key or identifier and raise an exception if the resource
           does not exist.
         * delete methods - delete an existing resource from the store. These
           methods should expect the resource to be correctly identified by its
           unique key or identifier. If the resource does not exist,
           an exception should be raised.
  
      Best practices for implementing and keeping this interface clean and easy to
      maintain and extend:
  
        * keep methods organized by resource type and ordered by CRUD operation
        * for resources with multiple keys, don't implement multiple get or list
        methods here if the same functionality can be achieved by a single get or
        list method. Instead, implement them in the BaseZenStore class and have
        them call the generic get or list method in this interface.
        * keep the logic required to convert between ZenML domain Model classes
        and internal store representations outside the ZenML domain Model classes
        * methods for resources that have two or more unique keys (e.g. a project
        is uniquely identified by its name as well as its UUID) should reflect
        that in the method variants and/or method arguments:
          * methods that take in a resource identifier as argument should accept
          all variants of the identifier (e.g. `project_name_or_uuid` for methods
          that get/list/update/delete projects)
          * if a compound key is involved, separate get methods should be
          implemented (e.g. `get_pipeline` to get a pipeline by ID and
          `get_pipeline_in_project` to get a pipeline by its name and the ID of
          the project it belongs to)
        * methods for resources that are scoped as children of other resources
        (e.g. a pipeline is always owned by a project) should reflect the
        key(s) of the parent resource in the provided method arguments:
          * list methods should feature optional filter arguments that reflect
          the parent resource key(s)
      """
  
      # ---------------------------------
      # Initialization and configuration
      # ---------------------------------
  
      @abstractmethod
      def _initialize(self) -> None:
          """Initialize the store.
  
          This method is called immediately after the store is created. It should
          be used to set up the backend (database, connection etc.).
          """
  
      @abstractmethod
      def get_store_info(self) -> ServerModel:
          """Get information about the store.
  
          Returns:
              Information about the store.
          """
  
      @abstractmethod
      def get_deployment_id(self) -> UUID:
          """Get the ID of the deployment.
  
          Returns:
              The ID of the deployment.
          """
  
      # -------------------- Server Settings --------------------
  
      @abstractmethod
      def get_server_settings(
          self, hydrate: bool = True
      ) -> ServerSettingsResponse:
          """Get the server settings.
  
          Args:
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The server settings.
          """
  
      @abstractmethod
      def update_server_settings(
          self, settings_update: ServerSettingsUpdate
      ) -> ServerSettingsResponse:
          """Update the server settings.
  
          Args:
              settings_update: The server settings update.
  
          Returns:
              The updated server settings.
          """
  
      # -------------------- Actions  --------------------
  
      @abstractmethod
      def create_action(self, action: ActionRequest) -> ActionResponse:
          """Create an action.
  
          Args:
              action: The action to create.
  
          Returns:
              The created action.
          """
  
      @abstractmethod
      def get_action(
          self,
          action_id: UUID,
          hydrate: bool = True,
      ) -> ActionResponse:
          """Get an action by ID.
  
          Args:
              action_id: The ID of the action to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The action.
  
          Raises:
              KeyError: If the action doesn't exist.
          """
  
      @abstractmethod
      def list_actions(
          self,
          action_filter_model: ActionFilter,
          hydrate: bool = False,
      ) -> Page[ActionResponse]:
          """List all actions matching the given filter criteria.
  
          Args:
              action_filter_model: All filter parameters including pagination
                  params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A list of all actions matching the filter criteria.
          """
  
      @abstractmethod
      def update_action(
          self,
          action_id: UUID,
          action_update: ActionUpdate,
      ) -> ActionResponse:
          """Update an existing action.
  
          Args:
              action_id: The ID of the action to update.
              action_update: The update to be applied to the action.
  
          Returns:
              The updated action.
  
          Raises:
              KeyError: If the action doesn't exist.
          """
  
      @abstractmethod
      def delete_action(self, action_id: UUID) -> None:
          """Delete an action.
  
          Args:
              action_id: The ID of the action to delete.
  
          Raises:
              KeyError: If the action doesn't exist.
          """
  
      # -------------------- API Keys --------------------
  
      @abstractmethod
      def create_api_key(
          self, service_account_id: UUID, api_key: APIKeyRequest
      ) -> APIKeyResponse:
          """Create a new API key for a service account.
  
          Args:
              service_account_id: The ID of the service account for which to
                  create the API key.
              api_key: The API key to create.
  
          Returns:
              The created API key.
  
          Raises:
              KeyError: If the service account doesn't exist.
              EntityExistsError: If an API key with the same name is already
                  configured for the same service account.
          """
  
      @abstractmethod
      def get_api_key(
          self,
          service_account_id: UUID,
          api_key_name_or_id: Union[str, UUID],
          hydrate: bool = True,
      ) -> APIKeyResponse:
          """Get an API key for a service account.
  
          Args:
              service_account_id: The ID of the service account for which to fetch
                  the API key.
              api_key_name_or_id: The name or ID of the API key to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The API key with the given ID.
  
          Raises:
              KeyError: if an API key with the given name or ID is not configured
                  for the given service account.
          """
  
      @abstractmethod
      def list_api_keys(
          self,
          service_account_id: UUID,
          filter_model: APIKeyFilter,
          hydrate: bool = False,
      ) -> Page[APIKeyResponse]:
          """List all API keys for a service account matching the given filter criteria.
  
          Args:
              service_account_id: The ID of the service account for which to list
                  the API keys.
              filter_model: All filter parameters including pagination
                  params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A list of all API keys matching the filter criteria.
          """
  
      @abstractmethod
      def update_api_key(
          self,
          service_account_id: UUID,
          api_key_name_or_id: Union[str, UUID],
          api_key_update: APIKeyUpdate,
      ) -> APIKeyResponse:
          """Update an API key for a service account.
  
          Args:
              service_account_id: The ID of the service account for which to update
                  the API key.
              api_key_name_or_id: The name or ID of the API key to update.
              api_key_update: The update request on the API key.
  
          Returns:
              The updated API key.
  
          Raises:
              KeyError: if an API key with the given name or ID is not configured
                  for the given service account.
              EntityExistsError: if the API key update would result in a name
                  conflict with an existing API key for the same service account.
          """
  
      @abstractmethod
      def rotate_api_key(
          self,
          service_account_id: UUID,
          api_key_name_or_id: Union[str, UUID],
          rotate_request: APIKeyRotateRequest,
      ) -> APIKeyResponse:
          """Rotate an API key for a service account.
  
          Args:
              service_account_id: The ID of the service account for which to
                  rotate the API key.
              api_key_name_or_id: The name or ID of the API key to rotate.
              rotate_request: The rotate request on the API key.
  
          Returns:
              The updated API key.
  
          Raises:
              KeyError: if an API key with the given name or ID is not configured
                  for the given service account.
          """
  
      @abstractmethod
      def delete_api_key(
          self,
          service_account_id: UUID,
          api_key_name_or_id: Union[str, UUID],
      ) -> None:
          """Delete an API key for a service account.
  
          Args:
              service_account_id: The ID of the service account for which to
                  delete the API key.
              api_key_name_or_id: The name or ID of the API key to delete.
  
          Raises:
              KeyError: if an API key with the given name or ID is not configured
                  for the given service account.
          """
  
      # -------------------- Services --------------------
  
      @abstractmethod
      def create_service(
          self,
          service: ServiceRequest,
      ) -> ServiceResponse:
          """Create a new service.
  
          Args:
              service: The service to create.
  
          Returns:
              The newly created service.
  
          Raises:
              EntityExistsError: If a service with the same name already exists.
          """
  
      @abstractmethod
      def get_service(
          self, service_id: UUID, hydrate: bool = True
      ) -> ServiceResponse:
          """Get a service by ID.
  
          Args:
              service_id: The ID of the service to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The service.
  
          Raises:
              KeyError: if the service doesn't exist.
          """
  
      @abstractmethod
      def list_services(
          self, filter_model: ServiceFilter, hydrate: bool = False
      ) -> Page[ServiceResponse]:
          """List all services matching the given filter criteria.
  
          Args:
              filter_model: All filter parameters including pagination
                  params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A list of all services matching the filter criteria.
          """
  
      @abstractmethod
      def update_service(
          self, service_id: UUID, update: ServiceUpdate
      ) -> ServiceResponse:
          """Update an existing service.
  
          Args:
              service_id: The ID of the service to update.
              update: The update to be applied to the service.
  
          Returns:
              The updated service.
  
          Raises:
              KeyError: if the service doesn't exist.
          """
  
      @abstractmethod
      def delete_service(self, service_id: UUID) -> None:
          """Delete a service.
  
          Args:
              service_id: The ID of the service to delete.
  
          Raises:
              KeyError: if the service doesn't exist.
          """
  
      # -------------------- Artifacts --------------------
  
      @abstractmethod
      def create_artifact(self, artifact: ArtifactRequest) -> ArtifactResponse:
          """Creates a new artifact.
  
          Args:
              artifact: The artifact to create.
  
          Returns:
              The newly created artifact.
  
          Raises:
              EntityExistsError: If an artifact with the same name already exists.
          """
  
      @abstractmethod
      def get_artifact(
          self, artifact_id: UUID, hydrate: bool = True
      ) -> ArtifactResponse:
          """Gets an artifact.
  
          Args:
              artifact_id: The ID of the artifact to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The artifact.
  
          Raises:
              KeyError: if the artifact doesn't exist.
          """
  
      @abstractmethod
      def list_artifacts(
          self, filter_model: ArtifactFilter, hydrate: bool = False
      ) -> Page[ArtifactResponse]:
          """List all artifacts matching the given filter criteria.
  
          Args:
              filter_model: All filter parameters including pagination
                  params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A list of all artifacts matching the filter criteria.
          """
  
      @abstractmethod
      def update_artifact(
          self, artifact_id: UUID, artifact_update: ArtifactUpdate
      ) -> ArtifactResponse:
          """Updates an artifact.
  
          Args:
              artifact_id: The ID of the artifact to update.
              artifact_update: The update to be applied to the artifact.
  
          Returns:
              The updated artifact.
  
          Raises:
              KeyError: if the artifact doesn't exist.
          """
  
      @abstractmethod
      def delete_artifact(self, artifact_id: UUID) -> None:
          """Deletes an artifact.
  
          Args:
              artifact_id: The ID of the artifact to delete.
  
          Raises:
              KeyError: if the artifact doesn't exist.
          """
  
      # -------------------- Artifact Versions --------------------
  
      @abstractmethod
      def create_artifact_version(
          self, artifact_version: ArtifactVersionRequest
      ) -> ArtifactVersionResponse:
          """Creates an artifact version.
  
          Args:
              artifact_version: The artifact version to create.
  
          Returns:
              The created artifact version.
          """
  
      @abstractmethod
      def batch_create_artifact_versions(
          self, artifact_versions: List[ArtifactVersionRequest]
      ) -> List[ArtifactVersionResponse]:
          """Creates a batch of artifact versions.
  
          Args:
              artifact_versions: The artifact versions to create.
  
          Returns:
              The created artifact versions.
          """
  
      @abstractmethod
      def get_artifact_version(
          self, artifact_version_id: UUID, hydrate: bool = True
      ) -> ArtifactVersionResponse:
          """Gets an artifact version.
  
          Args:
              artifact_version_id: The ID of the artifact version to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The artifact version.
  
          Raises:
              KeyError: if the artifact version doesn't exist.
          """
  
      @abstractmethod
      def list_artifact_versions(
          self,
          artifact_version_filter_model: ArtifactVersionFilter,
          hydrate: bool = False,
      ) -> Page[ArtifactVersionResponse]:
          """List all artifact versions matching the given filter criteria.
  
          Args:
              artifact_version_filter_model: All filter parameters including
                  pagination params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A list of all artifact versions matching the filter criteria.
          """
  
      @abstractmethod
      def update_artifact_version(
          self,
          artifact_version_id: UUID,
          artifact_version_update: ArtifactVersionUpdate,
      ) -> ArtifactVersionResponse:
          """Updates an artifact version.
  
          Args:
              artifact_version_id: The ID of the artifact version to update.
              artifact_version_update: The update to be applied to the artifact
                  version.
  
          Returns:
              The updated artifact version.
  
          Raises:
              KeyError: if the artifact version doesn't exist.
          """
  
      @abstractmethod
      def delete_artifact_version(self, artifact_version_id: UUID) -> None:
          """Deletes an artifact version.
  
          Args:
              artifact_version_id: The ID of the artifact version to delete.
  
          Raises:
              KeyError: if the artifact version doesn't exist.
          """
  
      @abstractmethod
      def prune_artifact_versions(
          self,
          project_name_or_id: Union[str, UUID],
          only_versions: bool = True,
      ) -> None:
          """Prunes unused artifact versions and their artifacts.
  
          Args:
              project_name_or_id: The project name or ID to prune artifact
                  versions for.
              only_versions: Only delete artifact versions, keeping artifacts
          """
  
      # -------------------- Artifact Visualization --------------------
  
      @abstractmethod
      def get_artifact_visualization(
          self, artifact_visualization_id: UUID, hydrate: bool = True
      ) -> ArtifactVisualizationResponse:
          """Gets an artifact visualization.
  
          Args:
              artifact_visualization_id: The ID of the artifact visualization
                  to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The artifact visualization.
  
          Raises:
              KeyError: if the artifact visualization doesn't exist.
          """
  
      # -------------------- Code References --------------------
  
      @abstractmethod
      def get_code_reference(
          self, code_reference_id: UUID, hydrate: bool = True
      ) -> CodeReferenceResponse:
          """Gets a specific code reference.
  
          Args:
              code_reference_id: The ID of the code reference to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The requested code reference, if it was found.
  
          Raises:
              KeyError: If no code reference with the given ID exists.
          """
  
      # -------------------- Code repositories --------------------
  
      @abstractmethod
      def create_code_repository(
          self, code_repository: CodeRepositoryRequest
      ) -> CodeRepositoryResponse:
          """Creates a new code repository.
  
          Args:
              code_repository: Code repository to be created.
  
          Returns:
              The newly created code repository.
  
          Raises:
              EntityExistsError: If a code repository with the given name already
                  exists.
          """
  
      @abstractmethod
      def get_code_repository(
          self, code_repository_id: UUID, hydrate: bool = True
      ) -> CodeRepositoryResponse:
          """Gets a specific code repository.
  
          Args:
              code_repository_id: The ID of the code repository to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The requested code repository, if it was found.
  
          Raises:
              KeyError: If no code repository with the given ID exists.
          """
  
      @abstractmethod
      def list_code_repositories(
          self, filter_model: CodeRepositoryFilter, hydrate: bool = False
      ) -> Page[CodeRepositoryResponse]:
          """List all code repositories.
  
          Args:
              filter_model: All filter parameters including pagination
                  params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A page of all code repositories.
          """
  
      @abstractmethod
      def update_code_repository(
          self, code_repository_id: UUID, update: CodeRepositoryUpdate
      ) -> CodeRepositoryResponse:
          """Updates an existing code repository.
  
          Args:
              code_repository_id: The ID of the code repository to update.
              update: The update to be applied to the code repository.
  
          Returns:
              The updated code repository.
  
          Raises:
              KeyError: If no code repository with the given name exists.
          """
  
      @abstractmethod
      def delete_code_repository(self, code_repository_id: UUID) -> None:
          """Deletes a code repository.
  
          Args:
              code_repository_id: The ID of the code repository to delete.
  
          Raises:
              KeyError: If no code repository with the given ID exists.
          """
  
      # -------------------- Components --------------------
  
      @abstractmethod
      def create_stack_component(
          self, component: ComponentRequest
      ) -> ComponentResponse:
          """Create a stack component.
  
          Args:
              component: The stack component to create.
  
          Returns:
              The created stack component.
  
          Raises:
              EntityExistsError: If a stack component with the same name
                  and type already exists.
          """
  
      @abstractmethod
      def get_stack_component(
          self,
          component_id: UUID,
          hydrate: bool = True,
      ) -> ComponentResponse:
          """Get a stack component by ID.
  
          Args:
              component_id: The ID of the stack component to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The stack component.
  
          Raises:
              KeyError: if the stack component doesn't exist.
          """
  
      @abstractmethod
      def list_stack_components(
          self,
          component_filter_model: ComponentFilter,
          hydrate: bool = False,
      ) -> Page[ComponentResponse]:
          """List all stack components matching the given filter criteria.
  
          Args:
              component_filter_model: All filter parameters including pagination
                  params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A list of all stack components matching the filter criteria.
          """
  
      @abstractmethod
      def update_stack_component(
          self,
          component_id: UUID,
          component_update: ComponentUpdate,
      ) -> ComponentResponse:
          """Update an existing stack component.
  
          Args:
              component_id: The ID of the stack component to update.
              component_update: The update to be applied to the stack component.
  
          Returns:
              The updated stack component.
  
          Raises:
              KeyError: if the stack component doesn't exist.
          """
  
      @abstractmethod
      def delete_stack_component(self, component_id: UUID) -> None:
          """Delete a stack component.
  
          Args:
              component_id: The ID of the stack component to delete.
  
          Raises:
              KeyError: if the stack component doesn't exist.
              ValueError: if the stack component is part of one or more stacks.
          """
  
      # -------------------- Devices --------------------
  
      @abstractmethod
      def get_authorized_device(
          self, device_id: UUID, hydrate: bool = True
      ) -> OAuthDeviceResponse:
          """Gets a specific OAuth 2.0 authorized device.
  
          Args:
              device_id: The ID of the device to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The requested device, if it was found.
  
          Raises:
              KeyError: If no device with the given ID exists.
          """
  
      @abstractmethod
      def list_authorized_devices(
          self, filter_model: OAuthDeviceFilter, hydrate: bool = False
      ) -> Page[OAuthDeviceResponse]:
          """List all OAuth 2.0 authorized devices for a user.
  
          Args:
              filter_model: All filter parameters including pagination
                  params.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              A page of all matching OAuth 2.0 authorized devices.
          """
  
      @abstractmethod
      def update_authorized_device(
          self, device_id: UUID, update: OAuthDeviceUpdate
      ) -> OAuthDeviceResponse:
          """Updates an existing OAuth 2.0 authorized device for internal use.
  
          Args:
              device_id: The ID of the device to update.
              update: The update to be applied to the device.
  
          Returns:
              The updated OAuth 2.0 authorized device.
  
          Raises:
              KeyError: If no device with the given ID exists.
          """
  
      @abstractmethod
      def delete_authorized_device(self, device_id: UUID) -> None:
          """Deletes an OAuth 2.0 authorized device.
  
          Args:
              device_id: The ID of the device to delete.
  
          Raises:
              KeyError: If no device with the given ID exists.
          """
  
      # -------------------- Flavors --------------------
  
      @abstractmethod
      def create_flavor(
          self,
          flavor: FlavorRequest,
      ) -> FlavorResponse:
          """Creates a new stack component flavor.
  
          Args:
              flavor: The stack component flavor to create.
  
          Returns:
              The newly created flavor.
  
          Raises:
              EntityExistsError: If a flavor with the same name and type
                  already exists.
          """
  
      @abstractmethod
      def get_flavor(
          self, flavor_id: UUID, hydrate: bool = True
      ) -> FlavorResponse:
          """Get a stack component flavor by ID.
  
          Args:
              flavor_id: The ID of the flavor to get.
              hydrate: Flag deciding whether to hydrate the output model(s)
                  by including metadata fields in the response.
  
          Returns:
              The stack component flavor.
  
          Raises:
              KeyError: if the stack component flavor doesn't exist.
          """
  
      @abstractmethod
      def update_flavor(
          self, flavor_id: UUID, flavor_update: FlavorUpdate
      ) -> FlavorResponse:
          """Updates an existing user.
  
          Args:
              flavor_id: The id of the flavor to update.
              flavor_update: The update to be applied to the flavor.
  
          Returns:
              The updated flavor.
          """
  
      @abstractmethod
      def list_flavors(
          self,
  