Spaces:
Sleeping
Sleeping
| from typing import Optional, Dict, Any, Union, List | |
| from pydantic import field_validator, Field | |
| from pydantic_core.core_schema import ValidationInfo | |
| from phi.infra.base import InfraBase | |
| from phi.app.context import ContainerContext | |
| from phi.resource.base import ResourceBase | |
| from phi.utils.log import logger | |
| class AppBase(InfraBase): | |
| # -*- App Name (required) | |
| name: str | |
| # -*- Image Configuration | |
| # Image can be provided as a DockerImage object | |
| image: Optional[Any] = None | |
| # OR as image_name:image_tag str | |
| image_str: Optional[str] = None | |
| # OR as image_name and image_tag | |
| image_name: Optional[str] = None | |
| image_tag: Optional[str] = None | |
| # Entrypoint for the container | |
| entrypoint: Optional[Union[str, List[str]]] = None | |
| # Command for the container | |
| command: Optional[Union[str, List[str]]] = None | |
| # -*- Python Configuration | |
| # Install python dependencies using a requirements.txt file | |
| install_requirements: bool = False | |
| # Path to the requirements.txt file relative to the workspace_root | |
| requirements_file: str = "requirements.txt" | |
| # Set the PYTHONPATH env var | |
| set_python_path: bool = True | |
| # Manually provide the PYTHONPATH. | |
| # If None, PYTHONPATH is set to workspace_root | |
| python_path: Optional[str] = None | |
| # Add paths to the PYTHONPATH env var | |
| # If python_path is provided, this value is ignored | |
| add_python_paths: Optional[List[str]] = None | |
| # -*- App Ports | |
| # Open a container port if open_port=True | |
| open_port: bool = False | |
| # If open_port=True, port_number is used to set the | |
| # container_port if container_port is None and host_port if host_port is None | |
| port_number: int = 80 | |
| # Port number on the Container to open | |
| # Preferred over port_number if both are set | |
| container_port: Optional[int] = Field(None, validate_default=True) | |
| # Port name for the opened port | |
| container_port_name: str = "http" | |
| # Port number on the Host to map to the Container port | |
| # Preferred over port_number if both are set | |
| host_port: Optional[int] = Field(None, validate_default=True) | |
| # -*- Extra Resources created "before" the App resources | |
| resources: Optional[List[ResourceBase]] = None | |
| # -*- Other args | |
| print_env_on_load: bool = False | |
| # -*- App specific args. Not to be set by the user. | |
| # Container Environment that can be set by subclasses | |
| # which is used as a starting point for building the container_env | |
| # Any variables set in container_env will be overridden by values | |
| # in the env_vars dict or env_file | |
| container_env: Optional[Dict[str, Any]] = None | |
| # Variable used to cache the container context | |
| container_context: Optional[ContainerContext] = None | |
| # -*- Cached Data | |
| cached_resources: Optional[List[Any]] = None | |
| def set_container_port(cls, v, info: ValidationInfo): | |
| port_number = info.data.get("port_number") | |
| if v is None and port_number is not None: | |
| v = port_number | |
| return v | |
| def set_host_port(cls, v, info: ValidationInfo): | |
| port_number = info.data.get("port_number") | |
| if v is None and port_number is not None: | |
| v = port_number | |
| return v | |
| def get_app_name(self) -> str: | |
| return self.name | |
| def get_image_str(self) -> str: | |
| if self.image: | |
| return f"{self.image.name}:{self.image.tag}" | |
| elif self.image_str: | |
| return self.image_str | |
| elif self.image_name and self.image_tag: | |
| return f"{self.image_name}:{self.image_tag}" | |
| elif self.image_name: | |
| return f"{self.image_name}:latest" | |
| else: | |
| return "" | |
| def build_resources(self, build_context: Any) -> Optional[Any]: | |
| logger.debug(f"@build_resource_group not defined for {self.get_app_name()}") | |
| return None | |
| def get_dependencies(self) -> Optional[List[ResourceBase]]: | |
| return ( | |
| [dep for dep in self.depends_on if isinstance(dep, ResourceBase)] if self.depends_on is not None else None | |
| ) | |
| def add_app_properties_to_resources(self, resources: List[ResourceBase]) -> List[ResourceBase]: | |
| updated_resources = [] | |
| app_properties = self.model_dump(exclude_defaults=True) | |
| app_group = self.get_group_name() | |
| app_output_dir = self.get_app_name() | |
| app_skip_create = app_properties.get("skip_create", None) | |
| app_skip_read = app_properties.get("skip_read", None) | |
| app_skip_update = app_properties.get("skip_update", None) | |
| app_skip_delete = app_properties.get("skip_delete", None) | |
| app_recreate_on_update = app_properties.get("recreate_on_update", None) | |
| app_use_cache = app_properties.get("use_cache", None) | |
| app_force = app_properties.get("force", None) | |
| app_debug_mode = app_properties.get("debug_mode", None) | |
| app_wait_for_create = app_properties.get("wait_for_create", None) | |
| app_wait_for_update = app_properties.get("wait_for_update", None) | |
| app_wait_for_delete = app_properties.get("wait_for_delete", None) | |
| app_save_output = app_properties.get("save_output", None) | |
| for resource in resources: | |
| resource_properties = resource.model_dump(exclude_defaults=True) | |
| resource_skip_create = resource_properties.get("skip_create", None) | |
| resource_skip_read = resource_properties.get("skip_read", None) | |
| resource_skip_update = resource_properties.get("skip_update", None) | |
| resource_skip_delete = resource_properties.get("skip_delete", None) | |
| resource_recreate_on_update = resource_properties.get("recreate_on_update", None) | |
| resource_use_cache = resource_properties.get("use_cache", None) | |
| resource_force = resource_properties.get("force", None) | |
| resource_debug_mode = resource_properties.get("debug_mode", None) | |
| resource_wait_for_create = resource_properties.get("wait_for_create", None) | |
| resource_wait_for_update = resource_properties.get("wait_for_update", None) | |
| resource_wait_for_delete = resource_properties.get("wait_for_delete", None) | |
| resource_save_output = resource_properties.get("save_output", None) | |
| # If skip_create on resource is not set, use app level skip_create (if set on app) | |
| if resource_skip_create is None and app_skip_create is not None: | |
| resource.skip_create = app_skip_create | |
| # If skip_read on resource is not set, use app level skip_read (if set on app) | |
| if resource_skip_read is None and app_skip_read is not None: | |
| resource.skip_read = app_skip_read | |
| # If skip_update on resource is not set, use app level skip_update (if set on app) | |
| if resource_skip_update is None and app_skip_update is not None: | |
| resource.skip_update = app_skip_update | |
| # If skip_delete on resource is not set, use app level skip_delete (if set on app) | |
| if resource_skip_delete is None and app_skip_delete is not None: | |
| resource.skip_delete = app_skip_delete | |
| # If recreate_on_update on resource is not set, use app level recreate_on_update (if set on app) | |
| if resource_recreate_on_update is None and app_recreate_on_update is not None: | |
| resource.recreate_on_update = app_recreate_on_update | |
| # If use_cache on resource is not set, use app level use_cache (if set on app) | |
| if resource_use_cache is None and app_use_cache is not None: | |
| resource.use_cache = app_use_cache | |
| # If force on resource is not set, use app level force (if set on app) | |
| if resource_force is None and app_force is not None: | |
| resource.force = app_force | |
| # If debug_mode on resource is not set, use app level debug_mode (if set on app) | |
| if resource_debug_mode is None and app_debug_mode is not None: | |
| resource.debug_mode = app_debug_mode | |
| # If wait_for_create on resource is not set, use app level wait_for_create (if set on app) | |
| if resource_wait_for_create is None and app_wait_for_create is not None: | |
| resource.wait_for_create = app_wait_for_create | |
| # If wait_for_update on resource is not set, use app level wait_for_update (if set on app) | |
| if resource_wait_for_update is None and app_wait_for_update is not None: | |
| resource.wait_for_update = app_wait_for_update | |
| # If wait_for_delete on resource is not set, use app level wait_for_delete (if set on app) | |
| if resource_wait_for_delete is None and app_wait_for_delete is not None: | |
| resource.wait_for_delete = app_wait_for_delete | |
| # If save_output on resource is not set, use app level save_output (if set on app) | |
| if resource_save_output is None and app_save_output is not None: | |
| resource.save_output = app_save_output | |
| # If workspace_settings on resource is not set, use app level workspace_settings (if set on app) | |
| if resource.workspace_settings is None and self.workspace_settings is not None: | |
| resource.set_workspace_settings(self.workspace_settings) | |
| # If group on resource is not set, use app level group (if set on app) | |
| if resource.group is None and app_group is not None: | |
| resource.group = app_group | |
| # Always set output_dir on resource to app level output_dir | |
| resource.output_dir = app_output_dir | |
| app_dependencies = self.get_dependencies() | |
| if app_dependencies is not None: | |
| if resource.depends_on is None: | |
| resource.depends_on = app_dependencies | |
| else: | |
| resource.depends_on.extend(app_dependencies) | |
| updated_resources.append(resource) | |
| return updated_resources | |
| def get_resources(self, build_context: Any) -> List[ResourceBase]: | |
| if self.cached_resources is not None and len(self.cached_resources) > 0: | |
| return self.cached_resources | |
| base_resources = self.resources or [] | |
| app_resources = self.build_resources(build_context) | |
| if app_resources is not None: | |
| base_resources.extend(app_resources) | |
| self.cached_resources = self.add_app_properties_to_resources(base_resources) | |
| # logger.debug(f"Resources: {self.cached_resources}") | |
| return self.cached_resources | |
| def matches_filters(self, group_filter: Optional[str] = None) -> bool: | |
| if group_filter is not None: | |
| group_name = self.get_group_name() | |
| logger.debug(f"{self.get_app_name()}: Checking {group_filter} in {group_name}") | |
| if group_name is None or group_filter not in group_name: | |
| return False | |
| return True | |
| def should_create(self, group_filter: Optional[str] = None) -> bool: | |
| if not self.enabled or self.skip_create: | |
| return False | |
| return self.matches_filters(group_filter) | |
| def should_delete(self, group_filter: Optional[str] = None) -> bool: | |
| if not self.enabled or self.skip_delete: | |
| return False | |
| return self.matches_filters(group_filter) | |
| def should_update(self, group_filter: Optional[str] = None) -> bool: | |
| if not self.enabled or self.skip_update: | |
| return False | |
| return self.matches_filters(group_filter) | |