From f683132e555cdf387031fed30c5cf51d783a81de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20=C3=87ayl=C4=B1?= <38523756+kaancayli@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:58:15 +0100 Subject: [PATCH] Adapt config. Replace None unions with Optional. Remove unnecessary files. --- app/common/custom_exceptions.py | 2 +- app/config.py | 5 +- app/dependencies.py | 2 +- app/domain/data/course_dto.py | 6 +- app/domain/data/feedback_dto.py | 4 +- app/domain/data/image_message_content_dto.py | 4 +- app/domain/data/json_message_content_dto.py | 4 +- app/domain/data/lecture_unit_dto.py | 5 +- app/domain/data/programming_exercise_dto.py | 6 +- app/domain/data/submission_dto.py | 6 +- app/domain/data/text_message_content_dto.py | 4 +- app/domain/data/user_dto.py | 6 +- app/domain/health_status_dto.py | 13 ---- app/domain/iris_message.py | 4 +- app/domain/model_dto.py | 4 +- app/domain/status/stage_dto.py | 16 ++--- app/domain/status/stage_state_dto.py | 2 +- .../tutor_chat_pipeline_execution_dto.py | 6 +- .../tutor_chat_status_update_dto.py | 4 +- app/main.py | 2 - app/pipeline/chat/tutor_chat_pipeline.py | 14 ++--- app/web/data/repository_fetch.py | 60 ------------------- app/web/routers/__init__.py | 1 - app/web/routers/health.py | 11 +++- app/web/routers/models.py | 8 --- application.test.yml | 5 +- 26 files changed, 64 insertions(+), 140 deletions(-) delete mode 100644 app/domain/health_status_dto.py delete mode 100644 app/web/data/repository_fetch.py delete mode 100644 app/web/routers/models.py diff --git a/app/common/custom_exceptions.py b/app/common/custom_exceptions.py index 7420fef5..1269433b 100644 --- a/app/common/custom_exceptions.py +++ b/app/common/custom_exceptions.py @@ -39,7 +39,7 @@ def __init__(self): super().__init__( status_code=status.HTTP_404_NOT_FOUND, detail={ - "type": "not_found", + "type": "pipeline_not_found", "errorMessage": "Pipeline not found", }, ) diff --git a/app/config.py b/app/config.py index 54d77168..02254449 100644 --- a/app/config.py +++ b/app/config.py @@ -9,10 +9,7 @@ class APIKeyConfig(BaseModel): class Settings(BaseModel): - class PyrisSettings(BaseModel): - api_keys: list[APIKeyConfig] - - pyris: PyrisSettings + api_keys: list[APIKeyConfig] @classmethod def get_settings(cls): diff --git a/app/dependencies.py b/app/dependencies.py index c47ebe2f..f9086662 100644 --- a/app/dependencies.py +++ b/app/dependencies.py @@ -19,7 +19,7 @@ def _get_api_key(request: Request) -> str: class TokenValidator: async def __call__(self, api_key: str = Depends(_get_api_key)) -> APIKeyConfig: - for key in settings.pyris.api_keys: + for key in settings.api_keys: if key.token == api_key: return key raise PermissionDeniedException diff --git a/app/domain/data/course_dto.py b/app/domain/data/course_dto.py index 3f20feff..78f80eae 100644 --- a/app/domain/data/course_dto.py +++ b/app/domain/data/course_dto.py @@ -1,7 +1,9 @@ +from typing import Optional + from pydantic import BaseModel class CourseDTO(BaseModel): id: int - name: str | None = None - description: str | None = None + name: Optional[str] = None + description: Optional[str] = None diff --git a/app/domain/data/feedback_dto.py b/app/domain/data/feedback_dto.py index da25d422..2615ef5e 100644 --- a/app/domain/data/feedback_dto.py +++ b/app/domain/data/feedback_dto.py @@ -1,8 +1,10 @@ +from typing import Optional + from pydantic import BaseModel, Field class FeedbackDTO(BaseModel): - text: str | None = None + text: Optional[str] = None test_case_name: str = Field(alias="testCaseName") credits: float diff --git a/app/domain/data/image_message_content_dto.py b/app/domain/data/image_message_content_dto.py index 8f2d56c6..d48fd717 100644 --- a/app/domain/data/image_message_content_dto.py +++ b/app/domain/data/image_message_content_dto.py @@ -1,5 +1,7 @@ +from typing import Optional + from pydantic import BaseModel, Field class ImageMessageContentDTO(BaseModel): - image_data: str | None = Field(alias="imageData", default=None) + image_data: Optional[str] = Field(alias="imageData", default=None) diff --git a/app/domain/data/json_message_content_dto.py b/app/domain/data/json_message_content_dto.py index 9889620b..73a0d7cb 100644 --- a/app/domain/data/json_message_content_dto.py +++ b/app/domain/data/json_message_content_dto.py @@ -1,6 +1,6 @@ from pydantic import BaseModel, Field, Json -from typing import Any +from typing import Any, Optional class JsonMessageContentDTO(BaseModel): - json_content: Json[Any] | None = Field(alias="jsonContent", default=None) + json_content: Optional[Json[Any]] = Field(alias="jsonContent", default=None) diff --git a/app/domain/data/lecture_unit_dto.py b/app/domain/data/lecture_unit_dto.py index 3d00e872..3e7b4d74 100644 --- a/app/domain/data/lecture_unit_dto.py +++ b/app/domain/data/lecture_unit_dto.py @@ -1,4 +1,5 @@ from datetime import datetime +from typing import Optional from pydantic import BaseModel, Field @@ -6,6 +7,6 @@ class LectureUnitDTO(BaseModel): id: int lecture_id: int = Field(alias="lectureId") - release_date: datetime | None = Field(alias="releaseDate", default=None) - name: str | None = None + release_date: Optional[datetime] = Field(alias="releaseDate", default=None) + name: Optional[str] = None attachment_version: int = Field(alias="attachmentVersion") diff --git a/app/domain/data/programming_exercise_dto.py b/app/domain/data/programming_exercise_dto.py index a2287de9..3f30c8d2 100644 --- a/app/domain/data/programming_exercise_dto.py +++ b/app/domain/data/programming_exercise_dto.py @@ -1,4 +1,4 @@ -from typing import Dict +from typing import Dict, Optional from pydantic import BaseModel, Field from datetime import datetime @@ -26,5 +26,5 @@ class ProgrammingExerciseDTO(BaseModel): solution_repository: Dict[str, str] = Field(alias="solutionRepository") test_repository: Dict[str, str] = Field(alias="testRepository") problem_statement: str = Field(alias="problemStatement") - start_date: datetime | None = Field(alias="startDate", default=None) - end_date: datetime | None = Field(alias="endDate", default=None) + start_date: Optional[datetime] = Field(alias="startDate", default=None) + end_date: Optional[datetime] = Field(alias="endDate", default=None) diff --git a/app/domain/data/submission_dto.py b/app/domain/data/submission_dto.py index 705ee33a..3574795c 100644 --- a/app/domain/data/submission_dto.py +++ b/app/domain/data/submission_dto.py @@ -1,4 +1,4 @@ -from typing import List, Dict +from typing import List, Dict, Optional from pydantic import BaseModel, Field @@ -9,11 +9,11 @@ class SubmissionDTO(BaseModel): id: int - date: datetime | None = None + date: Optional[datetime] = None repository: Dict[str, str] is_practice: bool = Field(alias="isPractice") build_failed: bool = Field(alias="buildFailed") build_log_entries: List[BuildLogEntryDTO] = Field( alias="buildLogEntries", default=[] ) - latest_result: ResultDTO | None = Field(alias="latestResult", default=None) + latest_result: Optional[ResultDTO] = Field(alias="latestResult", default=None) diff --git a/app/domain/data/text_message_content_dto.py b/app/domain/data/text_message_content_dto.py index ee3398a6..b7ece8f9 100644 --- a/app/domain/data/text_message_content_dto.py +++ b/app/domain/data/text_message_content_dto.py @@ -1,5 +1,7 @@ +from typing import Optional + from pydantic import BaseModel, Field class TextMessageContentDTO(BaseModel): - text_content: str | None = Field(alias="textContent", default=None) + text_content: Optional[str] = Field(alias="textContent", default=None) diff --git a/app/domain/data/user_dto.py b/app/domain/data/user_dto.py index ebd52d10..40832196 100644 --- a/app/domain/data/user_dto.py +++ b/app/domain/data/user_dto.py @@ -1,7 +1,9 @@ +from typing import Optional + from pydantic import BaseModel, Field class UserDTO(BaseModel): id: int - first_name: str | None = Field(alias="firstName", default=None) - last_name: str | None = Field(alias="lastName", default=None) + first_name: Optional[str] = Field(alias="firstName", default=None) + last_name: Optional[str] = Field(alias="lastName", default=None) diff --git a/app/domain/health_status_dto.py b/app/domain/health_status_dto.py deleted file mode 100644 index 4dcbca55..00000000 --- a/app/domain/health_status_dto.py +++ /dev/null @@ -1,13 +0,0 @@ -from pydantic import BaseModel -from enum import Enum - - -class ModelStatus(str, Enum): - UP = "UP" - DOWN = "DOWN" - NOT_AVAILABLE = "NOT_AVAILABLE" - - -class HealthStatusDTO(BaseModel): - model: str - status: ModelStatus diff --git a/app/domain/iris_message.py b/app/domain/iris_message.py index 30827efc..ac89666f 100644 --- a/app/domain/iris_message.py +++ b/app/domain/iris_message.py @@ -12,9 +12,7 @@ class IrisMessageRole(str, Enum): class IrisMessage(BaseModel): text: str = "" - role: Literal[ - IrisMessageRole.USER, IrisMessageRole.ASSISTANT, IrisMessageRole.SYSTEM - ] + role: IrisMessageRole def __str__(self): return f"{self.role.lower()}: {self.text}" diff --git a/app/domain/model_dto.py b/app/domain/model_dto.py index 7f962290..1a907204 100644 --- a/app/domain/model_dto.py +++ b/app/domain/model_dto.py @@ -1,7 +1,9 @@ +from typing import Optional + from pydantic import BaseModel class PyrisModelDTO(BaseModel): id: str name: str - description: str | None = None + description: Optional[str] = None diff --git a/app/domain/status/stage_dto.py b/app/domain/status/stage_dto.py index 75bef1f1..c050a2d0 100644 --- a/app/domain/status/stage_dto.py +++ b/app/domain/status/stage_dto.py @@ -1,18 +1,12 @@ -from typing import Literal +from typing import Literal, Optional from pydantic import BaseModel -from app.domain.status.stage_state_dto import StageStateDTO +from app.domain.status.stage_state_dto import StageStateEnum class StageDTO(BaseModel): - name: str | None = None + name: Optional[str] = None weight: int - state: Literal[ - StageStateDTO.NOT_STARTED, - StageStateDTO.IN_PROGRESS, - StageStateDTO.DONE, - StageStateDTO.SKIPPED, - StageStateDTO.ERROR, - ] - message: str | None = None + state: StageStateEnum + message: Optional[str] = None diff --git a/app/domain/status/stage_state_dto.py b/app/domain/status/stage_state_dto.py index 998b117e..8f6f447d 100644 --- a/app/domain/status/stage_state_dto.py +++ b/app/domain/status/stage_state_dto.py @@ -1,7 +1,7 @@ from enum import Enum -class StageStateDTO(str, Enum): +class StageStateEnum(str, Enum): NOT_STARTED = "NOT_STARTED" IN_PROGRESS = "IN_PROGRESS" DONE = "DONE" diff --git a/app/domain/tutor_chat/tutor_chat_pipeline_execution_dto.py b/app/domain/tutor_chat/tutor_chat_pipeline_execution_dto.py index 38c9fd00..8c1db7c9 100644 --- a/app/domain/tutor_chat/tutor_chat_pipeline_execution_dto.py +++ b/app/domain/tutor_chat/tutor_chat_pipeline_execution_dto.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Optional from pydantic import Field @@ -11,8 +11,8 @@ class TutorChatPipelineExecutionDTO(PipelineExecutionDTO): - submission: SubmissionDTO | None = None + submission: Optional[SubmissionDTO] = None exercise: ProgrammingExerciseDTO course: CourseDTO chat_history: List[MessageDTO] = Field(alias="chatHistory", default=[]) - user: UserDTO | None = None + user: Optional[UserDTO] = None diff --git a/app/domain/tutor_chat/tutor_chat_status_update_dto.py b/app/domain/tutor_chat/tutor_chat_status_update_dto.py index d516e5d6..c20002c3 100644 --- a/app/domain/tutor_chat/tutor_chat_status_update_dto.py +++ b/app/domain/tutor_chat/tutor_chat_status_update_dto.py @@ -1,5 +1,7 @@ +from typing import Optional + from ...domain.status.status_update_dto import StatusUpdateDTO class TutorChatStatusUpdateDTO(StatusUpdateDTO): - result: str | None = None + result: Optional[str] = None diff --git a/app/main.py b/app/main.py index 9e6eab84..f260d7d2 100644 --- a/app/main.py +++ b/app/main.py @@ -2,13 +2,11 @@ from fastapi import FastAPI from app.web.routers.health import router as health_router -from app.web.routers.models import router as models_router from app.web.routers.pipelines import router as pipelines_router from app.web.routers.webhooks import router as webhooks_router app = FastAPI(default_response_class=ORJSONResponse) app.include_router(health_router) -app.include_router(models_router) app.include_router(pipelines_router) app.include_router(webhooks_router) diff --git a/app/pipeline/chat/tutor_chat_pipeline.py b/app/pipeline/chat/tutor_chat_pipeline.py index 0dab2d2a..e3912719 100644 --- a/app/pipeline/chat/tutor_chat_pipeline.py +++ b/app/pipeline/chat/tutor_chat_pipeline.py @@ -18,7 +18,7 @@ final_system_prompt, guide_system_prompt, ) -from ...domain.status.stage_state_dto import StageStateDTO +from ...domain.status.stage_state_dto import StageStateEnum from ...domain import TutorChatPipelineExecutionDTO from ...domain.data.submission_dto import SubmissionDTO from ...domain.data.message_dto import MessageDTO @@ -104,7 +104,7 @@ def __call__(self, dto: TutorChatPipelineExecutionDTO, **kwargs): StageDTO( name="File lookup", weight=10, - state=StageStateDTO.IN_PROGRESS, + state=StageStateEnum.IN_PROGRESS, message="Looking up files in the repository...", ) ) @@ -123,7 +123,7 @@ def __call__(self, dto: TutorChatPipelineExecutionDTO, **kwargs): StageDTO( name="File lookup", weight=10, - state=StageStateDTO.DONE, + state=StageStateEnum.DONE, message="Looked up files in the repository.", ) ) @@ -133,7 +133,7 @@ def __call__(self, dto: TutorChatPipelineExecutionDTO, **kwargs): StageDTO( name="File lookup", weight=10, - state=StageStateDTO.SKIPPED, + state=StageStateEnum.SKIPPED, message=f"Failed to look up files in the repository: {e}", ) ) @@ -152,7 +152,7 @@ def __call__(self, dto: TutorChatPipelineExecutionDTO, **kwargs): StageDTO( name="Response generation", weight=10, - state=StageStateDTO.IN_PROGRESS, + state=StageStateEnum.IN_PROGRESS, message="Generating response...", ) ) @@ -178,7 +178,7 @@ def __call__(self, dto: TutorChatPipelineExecutionDTO, **kwargs): StageDTO( name="Response generation", weight=10, - state=StageStateDTO.DONE, + state=StageStateEnum.DONE, message="Generated response", ) ) @@ -188,7 +188,7 @@ def __call__(self, dto: TutorChatPipelineExecutionDTO, **kwargs): StageDTO( name="Response generation", weight=10, - state=StageStateDTO.ERROR, + state=StageStateEnum.ERROR, message=f"Failed to generate response: {e}", ) ) diff --git a/app/web/data/repository_fetch.py b/app/web/data/repository_fetch.py deleted file mode 100644 index f28d3707..00000000 --- a/app/web/data/repository_fetch.py +++ /dev/null @@ -1,60 +0,0 @@ -import os - -import requests -import zipfile -import tempfile - - -def get_student_submission(exercise_id: int, user_id: int, commit_hash: str) -> str: - unique_folder = f"repositories/{exercise_id}/users/{user_id}" - path = f"{unique_folder}/{commit_hash}" - if os.path.isdir(path): - return path - os.remove(unique_folder) - artemis_url = f"/api/v1/public/pyris/data/programming-exercises/{exercise_id}/submissions/{commit_hash}/repository" - _download(artemis_url, path) - return path - - -def get_template_repository(exercise_id: int, commit_hash: str) -> str: - unique_folder = f"repositories/{exercise_id}/template" - path = f"{unique_folder}/{commit_hash}" - if os.path.isdir(path): - return path - os.remove(unique_folder) - artemis_url = f"/api/v1/public/pyris/data/programming-exercises/{exercise_id}/repositories/template" - _download(artemis_url, path) - return path - - -def get_solution_repository(exercise_id: int, commit_hash: str) -> str: - unique_folder = f"repositories/{exercise_id}/solution" - path = f"{unique_folder}/{commit_hash}" - if os.path.isdir(path): - return path - os.remove(unique_folder) - artemis_url = f"/api/v1/public/pyris/data/programming-exercises/{exercise_id}/repositories/solution" - _download(artemis_url, path) - return path - - -def get_test_repository(exercise_id: int, commit_hash: str) -> str: - unique_folder = f"repositories/{exercise_id}/test" - path = f"{unique_folder}/{commit_hash}" - if os.path.isdir(path): - return path - os.remove(unique_folder) - artemis_url = f"/api/v1/public/pyris/data/programming-exercises/{exercise_id}/repositories/test" - _download(artemis_url, path) - return path - - -def _download(artemis_url: str, file_path: str): - os.makedirs(file_path, exist_ok=False) - with requests.get(artemis_url, stream=True) as result: - result.raise_for_status() - with tempfile.NamedTemporaryFile() as temp_file: - for chunk in result.iter_content(chunk_size=8 * 1024): - temp_file.write(chunk) - with zipfile.ZipFile(temp_file, "r") as zip_ref: - zip_ref.extractall(file_path) diff --git a/app/web/routers/__init__.py b/app/web/routers/__init__.py index 3f818435..58e2b00c 100644 --- a/app/web/routers/__init__.py +++ b/app/web/routers/__init__.py @@ -1,4 +1,3 @@ from ..routers.health import router as health_router -from ..routers.models import router as models_router from ..routers.pipelines import router as pipelines_router from ..routers.webhooks import router as webhooks_router diff --git a/app/web/routers/health.py b/app/web/routers/health.py index f48d44a0..7e0aba10 100644 --- a/app/web/routers/health.py +++ b/app/web/routers/health.py @@ -1,8 +1,13 @@ -from fastapi import APIRouter, status, Response +from fastapi import APIRouter, status, Response, Depends + +from app.dependencies import TokenValidator router = APIRouter(prefix="/api/v1/health", tags=["health"]) -@router.get("/") +@router.get( + "/", + dependencies=[Depends(TokenValidator())], +) def health_check(): - return Response(status_code=status.HTTP_501_NOT_IMPLEMENTED) + return Response(status_code=status.HTTP_200_OK) diff --git a/app/web/routers/models.py b/app/web/routers/models.py deleted file mode 100644 index f37d32fd..00000000 --- a/app/web/routers/models.py +++ /dev/null @@ -1,8 +0,0 @@ -from fastapi import APIRouter, status, Response - -router = APIRouter(prefix="/api/v1/models", tags=["models"]) - - -@router.get("/") -def read_models(): - return Response(status_code=status.HTTP_501_NOT_IMPLEMENTED) diff --git a/application.test.yml b/application.test.yml index 82ee5791..20629fac 100644 --- a/application.test.yml +++ b/application.test.yml @@ -1,3 +1,2 @@ -pyris: - api_keys: - - token: "secret" +api_keys: + - token: "secret"