Pipelinen parannuksia building blockeilla
This commit is contained in:
11
zipit/loop_runs/v6_stable/Dockerfile
Normal file
11
zipit/loop_runs/v6_stable/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
FROM python:3.12-slim
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
|
||||
ENV UV_CACHE_DIR=/tmp/uv-cache
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml .
|
||||
RUN uv sync
|
||||
COPY *.py .
|
||||
RUN useradd -m appuser
|
||||
USER appuser
|
||||
EXPOSE 8000
|
||||
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
62
zipit/loop_runs/v6_stable/main.py
Normal file
62
zipit/loop_runs/v6_stable/main.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from fastapi import FastAPI, HTTPException, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
|
||||
from models import Task, SessionLocal
|
||||
from schemas import TaskCreate, TaskResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Dependency to get database session
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@app.post("/tasks/", response_model=TaskResponse, status_code=201)
|
||||
def create_task(task: TaskCreate, db: Session = Depends(get_db)):
|
||||
db_task = Task(**task.model_dump())
|
||||
db.add(db_task)
|
||||
db.commit()
|
||||
db.refresh(db_task)
|
||||
return db_task
|
||||
|
||||
@app.get("/tasks/", response_model=List[TaskResponse])
|
||||
def read_tasks(status: str = None, db: Session = Depends(get_db)):
|
||||
if status:
|
||||
tasks = db.query(Task).filter_by(status=status).all()
|
||||
else:
|
||||
tasks = db.query(Task).all()
|
||||
return tasks
|
||||
|
||||
@app.get("/tasks/{task_id}", response_model=TaskResponse)
|
||||
def read_task(task_id: int, db: Session = Depends(get_db)):
|
||||
task = db.query(Task).filter(Task.id == task_id).first()
|
||||
if not task:
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
return task
|
||||
|
||||
@app.put("/tasks/{task_id}", response_model=TaskResponse)
|
||||
def update_task(task_id: int, task: TaskCreate, db: Session = Depends(get_db)):
|
||||
db_task = db.query(Task).filter(Task.id == task_id).first()
|
||||
if not db_task:
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
|
||||
for key, value in task.model_dump().items():
|
||||
setattr(db_task, key, value)
|
||||
|
||||
db.commit()
|
||||
db.refresh(db_task)
|
||||
return db_task
|
||||
|
||||
@app.delete("/tasks/{task_id}", status_code=204)
|
||||
def delete_task(task_id: int, db: Session = Depends(get_db)):
|
||||
db_task = db.query(Task).filter(Task.id == task_id).first()
|
||||
if not db_task:
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
|
||||
db.delete(db_task)
|
||||
db.commit()
|
||||
return
|
||||
23
zipit/loop_runs/v6_stable/models.py
Normal file
23
zipit/loop_runs/v6_stable/models.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Date, Enum
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
DATABASE_URL = "sqlite:///./todos.db"
|
||||
engine = create_engine(DATABASE_URL, connect_args={'check_same_thread': False})
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
Base = declarative_base()
|
||||
|
||||
class TaskStatus(Enum):
|
||||
pending = 'pending'
|
||||
completed = 'completed'
|
||||
|
||||
class Task(Base):
|
||||
__tablename__ = "tasks"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
title = Column(String(255), nullable=False)
|
||||
description = Column(String(1000))
|
||||
due_date = Column(Date)
|
||||
status = Column(Enum(TaskStatus), default=TaskStatus.pending)
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
15
zipit/loop_runs/v6_stable/pyproject.toml
Normal file
15
zipit/loop_runs/v6_stable/pyproject.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[project]
|
||||
name = "todo-app"
|
||||
version = "0.1.0"
|
||||
description = "A simple task management API using FastAPI and SQLAlchemy"
|
||||
authors = [
|
||||
{ name="Your Name", email="your.email@example.com" }
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
"fastapi",
|
||||
"uvicorn[standard]",
|
||||
"sqlalchemy",
|
||||
"python-dotenv",
|
||||
"pydantic"
|
||||
]
|
||||
126
zipit/loop_runs/v6_stable/report.json
Normal file
126
zipit/loop_runs/v6_stable/report.json
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"run_id": "v6_stable",
|
||||
"steps": [
|
||||
{
|
||||
"step": "requirements",
|
||||
"agent": "client",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt": 1,
|
||||
"elapsed": 7.7,
|
||||
"errors": [],
|
||||
"code_length": 1361
|
||||
}
|
||||
],
|
||||
"final_errors": [],
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"step": "models.py",
|
||||
"agent": "data",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt": 1,
|
||||
"elapsed": 5.9,
|
||||
"errors": [
|
||||
"SQLite create_engine puuttuu connect_args={'check_same_thread': False}",
|
||||
"Luokka 'TaskStatus' perii Enum:in mutta 'from enum import Enum' puuttuu (SQLAlchemy Enum ei ole Python Enum)"
|
||||
],
|
||||
"code_length": 751
|
||||
},
|
||||
{
|
||||
"attempt": 2,
|
||||
"elapsed": 5.6,
|
||||
"errors": [
|
||||
"Luokka 'TaskStatus' perii Enum:in mutta 'from enum import Enum' puuttuu (SQLAlchemy Enum ei ole Python Enum)"
|
||||
],
|
||||
"code_length": 794
|
||||
},
|
||||
{
|
||||
"attempt": 3,
|
||||
"elapsed": 5.5,
|
||||
"errors": [
|
||||
"Luokka 'TaskStatus' perii Enum:in mutta 'from enum import Enum' puuttuu (SQLAlchemy Enum ei ole Python Enum)"
|
||||
],
|
||||
"code_length": 794
|
||||
}
|
||||
],
|
||||
"final_errors": [
|
||||
"Luokka 'TaskStatus' perii Enum:in mutta 'from enum import Enum' puuttuu (SQLAlchemy Enum ei ole Python Enum)"
|
||||
],
|
||||
"passed": false
|
||||
},
|
||||
{
|
||||
"step": "schemas.py",
|
||||
"agent": "coder",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt": 1,
|
||||
"elapsed": 5.4,
|
||||
"errors": [],
|
||||
"code_length": 481
|
||||
}
|
||||
],
|
||||
"final_errors": [],
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"step": "main.py",
|
||||
"agent": "coder",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt": 1,
|
||||
"elapsed": 14.1,
|
||||
"errors": [],
|
||||
"code_length": 1914
|
||||
}
|
||||
],
|
||||
"final_errors": [],
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"step": "pyproject.toml",
|
||||
"agent": "coder",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt": 1,
|
||||
"elapsed": 3.6,
|
||||
"errors": [],
|
||||
"code_length": 304
|
||||
}
|
||||
],
|
||||
"final_errors": [],
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"step": "test_main.py",
|
||||
"agent": "qa",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt": 1,
|
||||
"elapsed": 16.9,
|
||||
"errors": [],
|
||||
"code_length": 2108
|
||||
}
|
||||
],
|
||||
"final_errors": [],
|
||||
"passed": true
|
||||
},
|
||||
{
|
||||
"step": "Dockerfile",
|
||||
"agent": "tester",
|
||||
"attempts": [
|
||||
{
|
||||
"attempt": 1,
|
||||
"elapsed": 4.0,
|
||||
"errors": [],
|
||||
"code_length": 291
|
||||
}
|
||||
],
|
||||
"final_errors": [],
|
||||
"passed": true
|
||||
}
|
||||
],
|
||||
"model": "qwen2.5-coder:7b-instruct-q4_K_M",
|
||||
"summary": "6/7 passed"
|
||||
}
|
||||
32
zipit/loop_runs/v6_stable/requirements
Normal file
32
zipit/loop_runs/v6_stable/requirements
Normal file
@@ -0,0 +1,32 @@
|
||||
**PROJECT NAME:** TodoSovellus
|
||||
|
||||
**GOAL:** Create a simple task management application for individuals to keep track of their daily tasks and manage them efficiently.
|
||||
|
||||
**CORE FEATURES:**
|
||||
1. **Add Task**: Users can add new tasks with a title, description, due date, and status (e.g., pending, completed).
|
||||
2. **View Tasks**: Users can view all tasks or filter by status (pending, completed).
|
||||
3. **Edit Task**: Users can update the details of an existing task.
|
||||
4. **Delete Task**: Users can remove tasks that are no longer needed.
|
||||
5. **Mark as Completed**: Users can mark a task as completed.
|
||||
6. **Filter Tasks**: Users can filter tasks based on their status (pending, completed).
|
||||
7. **Task Details**: Users can view detailed information about each task.
|
||||
|
||||
**DATA MODEL:**
|
||||
1. **Tasks**
|
||||
- id (integer, primary key)
|
||||
- title (string)
|
||||
- description (text)
|
||||
- due_date (date)
|
||||
- status (enum: pending, completed)
|
||||
|
||||
**API ENDPOINTS:**
|
||||
1. **GET /tasks**: Retrieve all tasks.
|
||||
2. **POST /tasks**: Create a new task.
|
||||
3. **GET /tasks/{id}**: Retrieve details of a specific task by ID.
|
||||
4. **PUT /tasks/{id}**: Update an existing task.
|
||||
5. **DELETE /tasks/{id}**: Delete a task.
|
||||
6. **GET /tasks/status/{status}**: Filter tasks by status (pending, completed).
|
||||
|
||||
**CONSTRAINTS:**
|
||||
- Must use SQLite as the database.
|
||||
- No authentication is required for accessing endpoints.
|
||||
18
zipit/loop_runs/v6_stable/schemas.py
Normal file
18
zipit/loop_runs/v6_stable/schemas.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import date
|
||||
|
||||
class TaskCreate(BaseModel):
|
||||
title: str = Field(..., min_length=1, max_length=255)
|
||||
description: str = Field(None, min_length=0, max_length=1000)
|
||||
due_date: date = Field(None)
|
||||
status: str = Field('pending', regex='^(pending|completed)$')
|
||||
|
||||
class TaskResponse(BaseModel):
|
||||
id: int
|
||||
title: str
|
||||
description: str
|
||||
due_date: date
|
||||
status: str
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
58
zipit/loop_runs/v6_stable/test_main.py
Normal file
58
zipit/loop_runs/v6_stable/test_main.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from main import app
|
||||
from models import Base
|
||||
from main import get_db
|
||||
|
||||
engine = create_engine("sqlite:///:memory:", connect_args={"check_same_thread": False})
|
||||
TestSession = sessionmaker(bind=engine)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
def override_get_db():
|
||||
db = TestSession()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
app.dependency_overrides[get_db] = override_get_db
|
||||
client = TestClient(app)
|
||||
|
||||
def test_create_task():
|
||||
response = client.post("/tasks/", json={"title": "Test Task", "description": "This is a test task"})
|
||||
assert response.status_code == 201
|
||||
assert response.json()["title"] == "Test Task"
|
||||
assert response.json()["status"] == "pending"
|
||||
|
||||
def test_read_tasks():
|
||||
response = client.get("/tasks/")
|
||||
assert response.status_code == 200
|
||||
assert len(response.json()) == 1
|
||||
|
||||
def test_get_task_by_id():
|
||||
task_response = client.post("/tasks/", json={"title": "Test Task", "description": "This is a test task"})
|
||||
task_id = task_response.json()["id"]
|
||||
response = client.get(f"/tasks/{task_id}")
|
||||
assert response.status_code == 200
|
||||
assert response.json()["id"] == task_id
|
||||
|
||||
def test_get_task_by_id_not_found():
|
||||
response = client.get("/tasks/999")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_update_task():
|
||||
task_response = client.post("/tasks/", json={"title": "Test Task", "description": "This is a test task"})
|
||||
task_id = task_response.json()["id"]
|
||||
update_data = {"title": "Updated Test Task"}
|
||||
response = client.put(f"/tasks/{task_id}", json=update_data)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["title"] == "Updated Test Task"
|
||||
|
||||
def test_delete_task():
|
||||
task_response = client.post("/tasks/", json={"title": "Test Task", "description": "This is a test task"})
|
||||
task_id = task_response.json()["id"]
|
||||
response = client.delete(f"/tasks/{task_id}")
|
||||
assert response.status_code == 204
|
||||
response = client.get(f"/tasks/{task_id}")
|
||||
assert response.status_code == 404
|
||||
Reference in New Issue
Block a user