Spaces:
Sleeping
Sleeping
File size: 4,224 Bytes
a07ae97 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | """Application configuration using pydantic-settings."""
from __future__ import annotations
import os
from enum import Enum
from pathlib import Path
from typing import Optional
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings
class EnvType(str, Enum):
CONDA = "conda"
VENV = "venv"
VENV_UV = "venv-uv"
class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
# Server settings
app_name: str = "MCP Code Executor"
debug: bool = False
host: str = "0.0.0.0"
port: int = 7860
# Code storage
code_storage_dir: str = Field(
default="/app/code_storage",
description="Directory where generated code files are stored",
)
# Environment configuration
env_type: EnvType = Field(default=EnvType.VENV_UV, description="Python environment type")
conda_env_name: Optional[str] = Field(default=None, description="Conda environment name")
venv_path: Optional[str] = Field(default=None, description="Path to virtualenv")
uv_venv_path: Optional[str] = Field(
default="/app/executor_venv", description="Path to UV virtualenv"
)
# Execution settings
execution_timeout: int = Field(
default=120, description="Maximum execution time in seconds", ge=5, le=600
)
max_concurrent_executions: int = Field(
default=20, description="Maximum concurrent code executions", ge=1, le=100
)
max_output_size: int = Field(
default=1_048_576, description="Maximum output size in bytes (1MB)", ge=1024
)
max_file_size: int = Field(
default=10_485_760, description="Maximum file size in bytes (10MB)", ge=1024
)
# HF Space
hf_space: bool = Field(default=False, description="Running on HuggingFace Space")
@field_validator("code_storage_dir")
@classmethod
def ensure_storage_dir_exists(cls, v: str) -> str:
path = Path(v)
path.mkdir(parents=True, exist_ok=True)
return str(path.resolve())
def get_python_executable(self) -> str:
"""Get the Python executable path for the configured environment."""
if self.env_type == EnvType.CONDA:
if not self.conda_env_name:
raise ValueError("CONDA_ENV_NAME must be set when ENV_TYPE is conda")
return f"conda run -n {self.conda_env_name} python"
elif self.env_type == EnvType.VENV:
if not self.venv_path:
raise ValueError("VENV_PATH must be set when ENV_TYPE is venv")
return str(Path(self.venv_path) / "bin" / "python")
elif self.env_type == EnvType.VENV_UV:
if not self.uv_venv_path:
raise ValueError("UV_VENV_PATH must be set when ENV_TYPE is venv-uv")
return str(Path(self.uv_venv_path) / "bin" / "python")
raise ValueError(f"Unknown environment type: {self.env_type}")
def get_pip_command(self) -> list[str]:
"""Get the pip install command for the configured environment."""
if self.env_type == EnvType.CONDA:
return ["conda", "install", "-n", self.conda_env_name, "-y"]
elif self.env_type == EnvType.VENV:
pip_path = str(Path(self.venv_path) / "bin" / "pip")
return [pip_path, "install"]
elif self.env_type == EnvType.VENV_UV:
return ["uv", "pip", "install", "--python", str(Path(self.uv_venv_path) / "bin" / "python")]
raise ValueError(f"Unknown environment type: {self.env_type}")
model_config = {
"env_prefix": "",
"case_sensitive": False,
"env_file": ".env",
"env_file_encoding": "utf-8",
}
# Singleton settings instance
_settings: Optional[Settings] = None
def get_settings() -> Settings:
"""Get or create the settings singleton."""
global _settings
if _settings is None:
_settings = Settings()
return _settings
def update_settings(**kwargs) -> Settings:
"""Update settings with new values (for dynamic configuration)."""
global _settings
current = get_settings()
new_data = current.model_dump()
new_data.update(kwargs)
_settings = Settings(**new_data)
return _settings |