Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion backend/app/api/routes/execution.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from dataclasses import asdict
from datetime import datetime, timezone
from typing import Annotated
from uuid import uuid4
Expand Down Expand Up @@ -336,7 +337,7 @@ async def get_k8s_resource_limits(
) -> ResourceLimits:
try:
limits = await execution_service.get_k8s_resource_limits()
return ResourceLimits(**vars(limits))
return ResourceLimits(**asdict(limits))
except Exception as e:
raise HTTPException(status_code=500, detail="Failed to retrieve resource limits") from e

Expand Down
2 changes: 2 additions & 0 deletions backend/app/domain/execution/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
from .models import (
DomainExecution,
ExecutionResultDomain,
LanguageInfoDomain,
ResourceLimitsDomain,
ResourceUsageDomain,
)

__all__ = [
"DomainExecution",
"ExecutionResultDomain",
"LanguageInfoDomain",
"ResourceLimitsDomain",
"ResourceUsageDomain",
"ExecutionServiceError",
Expand Down
10 changes: 9 additions & 1 deletion backend/app/domain/execution/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ def from_dict(data: dict[str, Any]) -> "ResourceUsageDomain":
)


@dataclass
class LanguageInfoDomain:
"""Language runtime information."""

versions: list[str]
file_ext: str


@dataclass
class ResourceLimitsDomain:
"""K8s resource limits configuration."""
Expand All @@ -73,4 +81,4 @@ class ResourceLimitsDomain:
cpu_request: str
memory_request: str
execution_timeout: int
supported_runtimes: dict[str, list[str]]
supported_runtimes: dict[str, LanguageInfoDomain]
2 changes: 1 addition & 1 deletion backend/app/domain/user/settings_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class DomainNotificationSettings:

@dataclass
class DomainEditorSettings:
theme: str = "one-dark"
theme: str = "auto"
font_size: int = 14
tab_size: int = 4
use_tabs: bool = False
Expand Down
7 changes: 6 additions & 1 deletion backend/app/runtime_registry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import NamedTuple, TypedDict

from app.domain.execution import LanguageInfoDomain


class RuntimeConfig(NamedTuple):
image: str # Full Docker image reference
Expand Down Expand Up @@ -178,4 +180,7 @@ def _make_runtime_configs() -> dict[str, dict[str, RuntimeConfig]]:

RUNTIME_REGISTRY: dict[str, dict[str, RuntimeConfig]] = _make_runtime_configs()

SUPPORTED_RUNTIMES: dict[str, list[str]] = {lang: list(versions.keys()) for lang, versions in RUNTIME_REGISTRY.items()}
SUPPORTED_RUNTIMES: dict[str, LanguageInfoDomain] = {
lang: LanguageInfoDomain(versions=spec["versions"], file_ext=spec["file_ext"])
for lang, spec in LANGUAGE_SPECS.items()
}
20 changes: 13 additions & 7 deletions backend/app/schemas_pydantic/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,12 @@ class ExecutionRequest(BaseModel):

@model_validator(mode="after")
def validate_runtime_supported(self) -> "ExecutionRequest": # noqa: D401
settings = get_settings()
runtimes = settings.SUPPORTED_RUNTIMES or {}
if self.lang not in runtimes:
runtimes = get_settings().SUPPORTED_RUNTIMES
if not (lang_info := runtimes.get(self.lang)):
raise ValueError(f"Language '{self.lang}' not supported. Supported: {list(runtimes.keys())}")
versions = runtimes.get(self.lang, [])
if self.lang_version not in versions:
raise ValueError(f"Version '{self.lang_version}' not supported for {self.lang}. Supported: {versions}")
if self.lang_version not in lang_info.versions:
raise ValueError(f"Version '{self.lang_version}' not supported for {self.lang}. "
f"Supported: {lang_info.versions}")
return self


Expand Down Expand Up @@ -108,6 +107,13 @@ class ExecutionResult(BaseModel):
model_config = ConfigDict(from_attributes=True)


class LanguageInfo(BaseModel):
"""Language runtime information."""

versions: list[str]
file_ext: str


class ResourceLimits(BaseModel):
"""Model for resource limits configuration."""

Expand All @@ -116,7 +122,7 @@ class ResourceLimits(BaseModel):
cpu_request: str
memory_request: str
execution_timeout: int
supported_runtimes: dict[str, list[str]]
supported_runtimes: dict[str, LanguageInfo]


class ExampleScripts(BaseModel):
Expand Down
8 changes: 1 addition & 7 deletions backend/app/schemas_pydantic/user_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,12 @@ class NotificationSettings(BaseModel):
class EditorSettings(BaseModel):
"""Code editor preferences"""

theme: str = "one-dark"
theme: str = "auto"
font_size: int = 14
tab_size: int = 4
use_tabs: bool = False
word_wrap: bool = True
show_line_numbers: bool = True
# These are always on in the editor, not user-configurable
font_family: str = "Monaco, Consolas, 'Courier New', monospace"
auto_complete: bool = True
bracket_matching: bool = True
highlight_active_line: bool = True
default_language: str = "python"

@field_validator("font_size")
@classmethod
Expand Down
7 changes: 6 additions & 1 deletion backend/app/services/execution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
from app.db.repositories.execution_repository import ExecutionRepository
from app.domain.enums.events import EventType
from app.domain.enums.execution import ExecutionStatus
from app.domain.execution import DomainExecution, ExecutionResultDomain, ResourceLimitsDomain, ResourceUsageDomain
from app.domain.execution import (
DomainExecution,
ExecutionResultDomain,
ResourceLimitsDomain,
ResourceUsageDomain,
)
from app.events.core import UnifiedProducer
from app.events.event_store import EventStore
from app.infrastructure.kafka.events.base import BaseEvent
Expand Down
3 changes: 2 additions & 1 deletion backend/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict

from app.domain.execution import LanguageInfoDomain
from app.runtime_registry import EXAMPLE_SCRIPTS as EXEC_EXAMPLE_SCRIPTS
from app.runtime_registry import SUPPORTED_RUNTIMES as RUNTIME_MATRIX

Expand Down Expand Up @@ -37,7 +38,7 @@ class Settings(BaseSettings):
K8S_POD_EXECUTION_TIMEOUT: int = 300 # in seconds
K8S_POD_PRIORITY_CLASS_NAME: str | None = None

SUPPORTED_RUNTIMES: dict[str, list[str]] = Field(default_factory=lambda: RUNTIME_MATRIX)
SUPPORTED_RUNTIMES: dict[str, LanguageInfoDomain] = Field(default_factory=lambda: RUNTIME_MATRIX)

EXAMPLE_SCRIPTS: dict[str, str] = Field(default_factory=lambda: EXEC_EXAMPLE_SCRIPTS)

Expand Down
2 changes: 1 addition & 1 deletion backend/tests/integration/test_user_settings_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ async def test_get_user_settings(self, client: AsyncClient, test_user: Dict[str,
assert settings.editor is not None
assert isinstance(settings.editor.font_size, int)
assert 8 <= settings.editor.font_size <= 32
assert settings.editor.theme in ["one-dark", "monokai", "github", "dracula", "solarized", "vs", "vscode"]
assert settings.editor.theme in ["auto", "one-dark", "monokai", "github", "dracula", "solarized", "vs", "vscode"]
assert isinstance(settings.editor.tab_size, int)
assert settings.editor.tab_size in [2, 4, 8]
assert isinstance(settings.editor.word_wrap, bool)
Expand Down
Loading
Loading