← run 2026-06-30T130601Z-3ea440b-minimal

gemma-4-26b-a4b@or — py-store-api

rep 1 PASS

pi 69.2s · verify 1.2s · 34427 tok · responded: google/gemma-4-26b-a4b-it · transcript

verify output
.........................                                                [100%]
25 passed in 0.66s
score: 25/25 (100%)
produced code
app.py
import os
import uuid
from typing import List, Optional, Dict
from fastapi import FastAPI, HTTPException, Depends, Query, status, Header
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field, validator

# --- Models ---

class User(BaseModel):
    username: str
    password: str

class LoginRequest(BaseModel):
    username: str
    password: str

class LoginResponse(BaseModel):
    token: str

class Product(BaseModel):
    id: int
    name: str
    price: float
    stock: int

class OrderRequest(BaseModel):
    product_id: int
    quantity: int

    @validator('quantity')
    def quantity_must_be_positive(cls, v):
        if v < 1:
            raise ValueError('quantity must be at least 1')
        return v

class Order(BaseModel):
    id: int
    product_id: int
    quantity: int
    total: float
    username: str  # Internal field to track owner

class OrderResponse(BaseModel):
    id: int
    product_id: int
    quantity: int
    total: float

# --- In-memory Data ---

users_db = {
    "alice": "password123",
    "bob": "hunter2"
}

# token -> username
tokens_db: Dict[str, str] = {}

products_db = [
    {"id": 1, "name": "Laptop", "price": 999.99, "stock": 10},
    {"id": 2, "name": "Mouse", "price": 25.50, "stock": 50},
    {"id": 3, "name": "Keyboard", "price": 75.00, "stock": 15},
]

orders_db = []
order_id_counter = 1

# --- App Setup ---

app = FastAPI()

# --- Dependencies ---

def get_current_user(authorization: Optional[str] = Header(None)) -> str:
    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Invalid or missing token")
    
    token = authorization.split(" ")[1]
    username = tokens_db.get(token)
    if not username:
        raise HTTPException(status_code=401, detail="Invalid or expired token")
    return username

# Custom exception handler for validation errors to match requirements (400 with JSON)
@app.exception_handler(Exception)
async def universal_exception_handler(request, exc):
    # This is a bit broad, let's refine it. 
    # FastAPI's default RequestValidationError returns 422. 
    # The prompt asks for 400 for malformed body.
    return JSONResponse(
        status_code=500,
        content={"error": str(exc)},
    )

# Overriding RequestValidationError to return 400 instead of 422
from fastapi.exceptions import RequestValidationError

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={"error": "Malformed request body or parameters"},
    )

# --- Routes ---

@app.post("/login", response_model=LoginResponse, status_code=200)
async def login(request: LoginRequest):
    if users_db.get(request.username) == request.password:
        token = str(uuid.uuid4())
        tokens_db[token] = request.username
        return {"token": token}
    else:
        raise HTTPException(status_code=401, detail="Invalid credentials")

@app.get("/products", response_model=List[Product])
async def get_products(max_price: Optional[float] = Query(None)):
    results = products_db
    if max_price is not None:
        # If max_price is not a valid float, FastAPI will raise RequestValidationError 
        # which we handle as 400.
        results = [p for p in products_db if p["price"] <= max_price]
    return results

@app.get("/products/{product_id}", response_model=Product)
async def get_product(product_id: int):
    product = next((p for p in products_db if p["id"] == product_id), None)
    if not product:
        raise HTTPException(status_code=404, detail="Product not found")
    return product

@app.post("/orders", response_model=OrderResponse, status_code=201)
async def create_order(order_req: OrderRequest, username: str = Depends(get_current_user)):
    global order_id_counter
    
    # Find product
    product = next((p for p in products_db if p["id"] == order_req.product_id), None)
    if not product:
        raise HTTPException(status_code=404, detail="Product not found")
    
    # Check stock
    if product["stock"] < order_req.quantity:
        raise HTTPException(status_code=409, detail="Insufficient stock")
    
    # Process order
    total = product["price"] * order_req.quantity
    new_order = {
        "id": order_id_counter,
        "product_id": order_req.product_id,
        "quantity": order_req.quantity,
        "total": total,
        "username": username
    }
    
    # Update stock
    product["stock"] -= order_req.quantity
    
    orders_db.append(new_order)
    order_id_counter += 1
    
    return new_order

@app.get("/orders", response_model=List[OrderResponse])
async def get_orders(username: str = Depends(get_current_user)):
    user_orders = [o for o in orders_db if o["username"] == username]
    return user_orders

@app.get("/orders/{order_id}", response_model=OrderResponse)
async def get_order(order_id: int, username: str = Depends(get_current_user)):
    order = next((o for o in orders_db if o["id"] == order_id), None)
    
    if not order or order["username"] != username:
        raise HTTPException(status_code=404, detail="Order not found")
    
    return order

# --- Error handling for 401/404/400 to ensure JSON response ---

@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
    return JSONResponse(
        status_code=exc.status_code,
        content={"error": exc.detail},
    )

if __name__ == "__main__":
    import uvicorn
    host = os.environ.get("HOST", "127.0.0.1")
    port = int(os.environ.get("PORT", 8000))
    uvicorn.run(app, host=host, port=port)
requirements.txt
fastapi
uvicorn

rep 2 PARTIAL 0/25

pi 95.5s · verify 0.4s · 4696 tok · responded: google/gemma-4-26b-a4b-it · transcript

verify output
EEEEEEEEEEEEEEEEEEEEEEEEE                                                [100%]
==================================== ERRORS ====================================
_____________________ ERROR at setup of test_login_success _____________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
___________________ ERROR at setup of test_login_second_user ___________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
__________________ ERROR at setup of test_login_bad_password ___________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
__________________ ERROR at setup of test_login_unknown_user ___________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_____________________ ERROR at setup of test_list_products _____________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
______________________ ERROR at setup of test_get_product ______________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
__________________ ERROR at setup of test_get_missing_product __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_________________ ERROR at setup of test_orders_requires_auth __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_______________ ERROR at setup of test_orders_rejects_bad_token ________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
________________ ERROR at setup of test_create_order_and_total _________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_____________ ERROR at setup of test_create_order_missing_product ______________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
__________________ ERROR at setup of test_orders_are_per_user __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_________________ ERROR at setup of test_login_malformed_json __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_________________ ERROR at setup of test_login_missing_fields __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_________________ ERROR at setup of test_order_malformed_json __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_________________ ERROR at setup of test_order_missing_fields __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_______________ ERROR at setup of test_order_non_integer_fields ________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
____________ ERROR at setup of test_order_zero_or_negative_quantity ____________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
__________________ ERROR at setup of test_products_have_stock __________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
________________ ERROR at setup of test_order_decrements_stock _________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
____________ ERROR at setup of test_order_exceeding_stock_conflict _____________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_____________________ ERROR at setup of test_get_own_order _____________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
___________________ ERROR at setup of test_get_missing_order ___________________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_____________ ERROR at setup of test_get_other_users_order_is_404 ______________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
_______________ ERROR at setup of test_products_max_price_filter _______________

    @pytest.fixture(scope="session")
    def base_url():
        app_py = os.path.join(APP_DIR, "app.py")
        if not os.path.isfile(app_py):
>           pytest.fail(f"app.py not found in {APP_DIR} (the model did not create it)")
E           Failed: app.py not found in /tmp/bench-ws-it75eqa8 (the model did not create it)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:99: Failed
=========================== short test summary info ============================
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_success
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_second_user
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_bad_password
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_unknown_user
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_list_products
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_get_product
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_get_missing_product
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_orders_requires_auth
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_orders_rejects_bad_token
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_create_order_and_total
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_create_order_missing_product
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_orders_are_per_user
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_malformed_json
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_missing_fields
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_malformed_json
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_missing_fields
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_non_integer_fields
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_zero_or_negative_quantity
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_products_have_stock
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_decrements_stock
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_exceeding_stock_conflict
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_get_own_order
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_get_missing_order
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_get_other_users_order_is_404
ERROR ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_products_max_price_filter
25 errors in 0.12s
score: 0/25 (0%)
produced code
requirements.txt
fastapi
uvicorn

rep 3 PASS

pi 388.9s · verify 0.9s · 76135 tok · responded: google/gemma-4-26b-a4b-it · transcript

verify output
.........................                                                [100%]
25 passed in 0.60s
score: 25/25 (100%)
produced code
app.py
import os
import secrets
from typing import List, Optional, Dict
from fastapi import FastAPI, Header, HTTPException, Query, status, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel, ValidationError
import uvicorn

# --- Models ---

class LoginRequest(BaseModel):
    username: str
    password: str

class LoginResponse(BaseModel):
    token: str

class Product(BaseModel):
    id: int
    name: str
    price: float
    stock: int

class OrderRequest(BaseModel):
    product_id: int
    quantity: int

class Order(BaseModel):
    id: int
    product_id: int
    quantity: int
    total: float
    username: str # Internal use for tracking ownership

class OrderResponse(BaseModel):
    id: int
    product_id: int
    quantity: int
    total: float

# --- In-memory Data Store ---

users_db = {
    "alice": "password123",
    "bob": "hunter2"
}

# tokens maps token -> username
tokens_db: Dict[str, str] = {}

products_db = [
    {"id": 1, "name": "Laptop", "price": 999.99, "stock": 10},
    {"id": 2, "name": "Mouse", "price": 25.50, "stock": 50},
    {"id": 3, "name": "Keyboard", "price": 75.00, "stock": 20},
]

orders_db: List[Order] = []
order_counter = 1

# --- App Setup ---

app = FastAPI()

# --- Helpers ---

def get_user_from_token(authorization: str = Header(None)) -> str:
    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Missing or invalid token")
    
    token = authorization.split(" ")[1]
    username = tokens_db.get(token)
    if not username:
        raise HTTPException(status_code=401, detail="Invalid token")
    return username

# --- Endpoints ---

@app.post("/login")
async def login(request: Request):
    try:
        body = await request.json()
    except Exception:
        return JSONResponse(status_code=400, content={"error": "Malformed JSON"})

    if not isinstance(body, dict) or "username" not in body or "password" not in body:
        return JSONResponse(status_code=400, content={"error": "Missing username or password"})

    username = body["username"]
    password = body["password"]

    if users_db.get(username) == password:
        token = secrets.token_hex(16)
        tokens_db[token] = username
        return JSONResponse(status_code=200, content={"token": token})
    else:
        return JSONResponse(status_code=401, content={"error": "Invalid credentials"})

@app.get("/products")
async def get_products(max_price: Optional[str] = Query(None)):
    filtered_products = products_db
    if max_price is not None:
        try:
            mp = float(max_price)
            filtered_products = [p for p in products_db if p["price"] <= mp]
        except ValueError:
            pass
    return filtered_products

@app.get("/products/{product_id}")
async def get_product(product_id: int):
    product = next((p for p in products_db if p["id"] == product_id), None)
    if not product:
        return JSONResponse(status_code=404, content={"error": "Product not found"})
    return product

@app.post("/orders")
async def create_order(request: Request, authorization: str = Header(None)):
    try:
        username = get_user_from_token(authorization)
    except HTTPException as e:
        return JSONResponse(status_code=e.status_code, content={"error": e.detail})

    try:
        body = await request.json()
    except Exception:
        return JSONResponse(status_code=400, content={"error": "Malformed JSON"})

    if not isinstance(body, dict) or "product_id" not in body or "quantity" not in body:
        return JSONResponse(status_code=400, content={"error": "Missing product_id or quantity"})
    
    if not isinstance(body["product_id"], int) or not isinstance(body["quantity"], int):
        return JSONResponse(status_code=400, content={"error": "product_id and quantity must be integers"})

    product_id = body["product_id"]
    quantity = body["quantity"]

    if quantity < 1:
        return JSONResponse(status_code=400, content={"error": "quantity must be at least 1"})

    # Find product
    product = next((p for p in products_db if p["id"] == product_id), None)
    if not product:
        return JSONResponse(status_code=404, content={"error": "Product not found"})

    # Check stock
    if product["stock"] < quantity:
        return JSONResponse(status_code=409, content={"error": "Insufficient stock"})

    # Create order
    global order_counter
    total = product["price"] * quantity
    new_order = Order(
        id=order_counter,
        product_id=product_id,
        quantity=quantity,
        total=total,
        username=username
    )
    
    # Update stock
    product["stock"] -= quantity
    
    # Save order
    orders_db.append(new_order)
    order_counter += 1

    return JSONResponse(status_code=201, content={
        "id": new_order.id,
        "product_id": new_order.product_id,
        "quantity": new_order.quantity,
        "total": new_order.total
    })

@app.get("/orders")
async def get_orders(authorization: str = Header(None)):
    try:
        username = get_user_from_token(authorization)
    except HTTPException as e:
        return JSONResponse(status_code=e.status_code, content={"error": e.detail})

    user_orders = [
        {"id": o.id, "product_id": o.product_id, "quantity": o.quantity, "total": o.total}
        for o in orders_db if o.username == username
    ]
    return user_orders

@app.get("/orders/{order_id}")
async def get_order(order_id: int, authorization: str = Header(None)):
    try:
        username = get_user_from_token(authorization)
    except HTTPException as e:
        return JSONResponse(status_code=e.status_code, content={"error": e.detail})

    order = next((o for o in orders_db if o.id == order_id), None)
    
    if not order or order.username != username:
        return JSONResponse(status_code=404, content={"error": "Order not found"})
    
    return {"id": order.id, "product_id": order.product_id, "quantity": order.quantity, "total": order.total}

if __name__ == "__main__":
    host = os.environ.get("HOST", "127.0.0.1")
    port = int(os.environ.get("PORT", 8000))
    uvicorn.run(app, host=host, port=port)
requirements.txt
fastapi
uvicorn
test_api.py
import os
import time
import subprocess
import signal
import requests

def test_api():
    base_url = "http://127.0.0.1:8000"
    
    print("--- Starting Test Suite ---")

    # 1. Test GET /products (Public)
    print("Testing GET /products...")
    resp = requests.get(f"{base_url}/products")
    assert resp.status_code == 200
    products = resp.json()
    assert len(products) >= 3
    print("  PASSED")

    # 2. Test GET /products?max_price=50
    print("Testing GET /products?max_price=50...")
    resp = requests.get(f"{base_url}/products", params={"max_price": 50})
    assert resp.status_code == 200
    products = resp.json()
    for p in products:
        assert p["price"] <= 50
    print("  PASSED")

    # 3. Test GET /products/1
    print("Testing GET /products/1...")
    resp = requests.get(f"{base_url}/products/1")
    assert resp.status_code == 200
    assert resp.json()["id"] == 1
    print("  PASSED")

    # 4. Test GET /products/999 (Non-existent)
    print("Testing GET /products/999...")
    resp = requests.get(f"{base_url}/products/999")
    assert resp.status_code == 404
    assert "error" in resp.json()
    print("  PASSED")

    # 5. Test /login (Valid)
    print("Testing /login (Valid)...")
    resp = requests.post(f"{base_url}/login", json={"username": "alice", "password": "password123"})
    assert resp.status_code == 200
    token = resp.json()["token"]
    assert len(token) > 0
    print("  PASSED")

    # 6. Test /login (Invalid)
    print("Testing /login (Invalid)...")
    resp = requests.post(f"{base_url}/login", json={"username": "alice", "password": "wrong"})
    assert resp.status_code == 401
    print("  PASSED")

    # 7. Test /login (Malformed)
    print("Testing /login (Malformed)...")
    resp = requests.post(f"{base_url}/login", data="not a json")
    assert resp.status_code == 400
    print("  PASSED")

    # 8. Test /orders (Protected - Valid)
    print("Testing POST /orders (Valid)...")
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.post(f"{base_url}/orders", json={"product_id": 1, "quantity": 2}, headers=headers)
    assert resp.status_code == 201
    order = resp.json()
    assert order["product_id"] == 1
    assert order["quantity"] == 2
    assert order["total"] == 999.99 * 2
    print("  PASSED")

    # 9. Test /orders (Protected - Insufficient Stock)
    print("Testing POST /orders (Insufficient Stock)...")
    resp = requests.post(f"{base_url}/orders", json={"product_id": 1, "quantity": 100}, headers=headers)
    assert resp.status_code == 409
    print("  PASSED")

    # 10. Test /orders (Protected - Invalid Product)
    print("Testing POST /orders (Invalid Product)...")
    resp = requests.post(f"{base_url}/orders", json={"product_id": 999, "quantity": 1}, headers=headers)
    assert resp.status_code == 404
    print("  PASSED")

    # 11. Test GET /orders (Protected - User's own orders)
    print("Testing GET /orders (User's own orders)...")
    resp = requests.get(f"{base_url}/orders", headers=headers)
    assert resp.status_code == 200
    orders = resp.json()
    assert len(orders) > 0
    assert orders[0]["id"] == order["id"]
    print("  PASSED")

    # 12. Test GET /orders/{id} (Protected - Own order)
    print("Testing GET /orders/{id} (Own order)...")
    resp = requests.get(f"{base_url}/orders/{order['id']}", headers=headers)
    assert resp.status_code == 200
    print("  PASSED")

    # 13. Test GET /orders/{id} (Protected - Another user's order)
    print("Testing GET /orders/{id} (Another user's order)...")
    # Login as bob
    resp_bob = requests.post(f"{base_url}/login", json={"username": "bob", "password": "hunter2"})
    token_bob = resp_bob.json()["token"]
    headers_bob = {"Authorization": f"Bearer {token_bob}"}
    
    resp = requests.get(f"{base_url}/orders/{order['id']}", headers=headers_bob)
    assert resp.status_code == 404
    print("  PASSED")

    print("\n--- ALL TESTS PASSED ---")

if __name__ == "__main__":
    # Start server in a subprocess
    print("Starting server...")
    server_proc = subprocess.Popen(["python3", "app.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    # Wait for server to start
    time.sleep(3)

    try:
        test_api()
    except Exception as e:
        print(f"\nTEST FAILED: {e}")
        import traceback
        traceback.print_exc()
    finally:
        print("Shutting down server...")
        server_proc.terminate()
        server_proc.wait()

rep 4 PARTIAL 20/25

pi 468.4s · verify 1.0s · 292642 tok · responded: google/gemma-4-26b-a4b-it · transcript

verify output
............FFFFF........                                                [100%]
=================================== FAILURES ===================================
__________________________ test_login_malformed_json ___________________________

base_url = 'http://127.0.0.1:58759'

    def test_login_malformed_json(base_url):
        status, parsed, ct = _request_h("POST", f"{base_url}/login", raw_body="{not valid json")
>       _assert_json_error(status, parsed, ct, 400)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:261: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

status = 422
parsed = {'detail': [{'ctx': {'error': 'Expecting property name enclosed in double quotes'}, 'input': {}, 'loc': ['body', 1], 'msg': 'JSON decode error', ...}]}
ct = 'application/json', expect_status = 400

    def _assert_json_error(status, parsed, ct, expect_status):
        """A 4xx response must be JSON with an error/message field (see task.md 'Notes')."""
>       assert status == expect_status, f"expected {expect_status}, got {status} (body={parsed!r})"
E       AssertionError: expected 400, got 422 (body={'detail': [{'type': 'json_invalid', 'loc': ['body', 1], 'msg': 'JSON decode error', 'input': {}, 'ctx': {'error': 'Expecting property name enclosed in double quotes'}}]})
E       assert 422 == 400

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:89: AssertionError
__________________________ test_login_missing_fields ___________________________

base_url = 'http://127.0.0.1:58759'

    def test_login_missing_fields(base_url):
        status, parsed, ct = _request_h("POST", f"{base_url}/login", body={"username": "alice"})
>       _assert_json_error(status, parsed, ct, 400)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:266: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

status = 422
parsed = {'detail': [{'input': {'username': 'alice'}, 'loc': ['body', 'password'], 'msg': 'Field required', 'type': 'missing'}]}
ct = 'application/json', expect_status = 400

    def _assert_json_error(status, parsed, ct, expect_status):
        """A 4xx response must be JSON with an error/message field (see task.md 'Notes')."""
>       assert status == expect_status, f"expected {expect_status}, got {status} (body={parsed!r})"
E       AssertionError: expected 400, got 422 (body={'detail': [{'type': 'missing', 'loc': ['body', 'password'], 'msg': 'Field required', 'input': {'username': 'alice'}}]})
E       assert 422 == 400

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:89: AssertionError
__________________________ test_order_malformed_json ___________________________

base_url = 'http://127.0.0.1:58759'
alice_token = '266bce8b-f3b2-4ffa-a0e4-c860ff61fa74'

    def test_order_malformed_json(base_url, alice_token):
        status, parsed, ct = _request_h("POST", f"{base_url}/orders", token=alice_token,
                                        raw_body="definitely not json")
>       _assert_json_error(status, parsed, ct, 400)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:272: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

status = 422
parsed = {'detail': [{'ctx': {'error': 'Expecting value'}, 'input': {}, 'loc': ['body', 0], 'msg': 'JSON decode error', ...}]}
ct = 'application/json', expect_status = 400

    def _assert_json_error(status, parsed, ct, expect_status):
        """A 4xx response must be JSON with an error/message field (see task.md 'Notes')."""
>       assert status == expect_status, f"expected {expect_status}, got {status} (body={parsed!r})"
E       AssertionError: expected 400, got 422 (body={'detail': [{'type': 'json_invalid', 'loc': ['body', 0], 'msg': 'JSON decode error', 'input': {}, 'ctx': {'error': 'Expecting value'}}]})
E       assert 422 == 400

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:89: AssertionError
__________________________ test_order_missing_fields ___________________________

base_url = 'http://127.0.0.1:58759'
alice_token = '266bce8b-f3b2-4ffa-a0e4-c860ff61fa74'

    def test_order_missing_fields(base_url, alice_token):
        status, parsed, ct = _request_h("POST", f"{base_url}/orders", token=alice_token,
                                        body={"product_id": 1})
>       _assert_json_error(status, parsed, ct, 400)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:278: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

status = 422
parsed = {'detail': [{'input': {'product_id': 1}, 'loc': ['body', 'quantity'], 'msg': 'Field required', 'type': 'missing'}]}
ct = 'application/json', expect_status = 400

    def _assert_json_error(status, parsed, ct, expect_status):
        """A 4xx response must be JSON with an error/message field (see task.md 'Notes')."""
>       assert status == expect_status, f"expected {expect_status}, got {status} (body={parsed!r})"
E       AssertionError: expected 400, got 422 (body={'detail': [{'type': 'missing', 'loc': ['body', 'quantity'], 'msg': 'Field required', 'input': {'product_id': 1}}]})
E       assert 422 == 400

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:89: AssertionError
________________________ test_order_non_integer_fields _________________________

base_url = 'http://127.0.0.1:58759'
alice_token = '266bce8b-f3b2-4ffa-a0e4-c860ff61fa74'

    def test_order_non_integer_fields(base_url, alice_token):
        status, parsed, ct = _request_h("POST", f"{base_url}/orders", token=alice_token,
                                        body={"product_id": "abc", "quantity": "two"})
>       _assert_json_error(status, parsed, ct, 400)

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:284: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

status = 422
parsed = {'detail': [{'input': 'abc', 'loc': ['body', 'product_id'], 'msg': 'Input should be a valid integer, unable to parse s..., 'quantity'], 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'type': 'int_parsing'}]}
ct = 'application/json', expect_status = 400

    def _assert_json_error(status, parsed, ct, expect_status):
        """A 4xx response must be JSON with an error/message field (see task.md 'Notes')."""
>       assert status == expect_status, f"expected {expect_status}, got {status} (body={parsed!r})"
E       AssertionError: expected 400, got 422 (body={'detail': [{'type': 'int_parsing', 'loc': ['body', 'product_id'], 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': 'abc'}, {'type': 'int_parsing', 'loc': ['body', 'quantity'], 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': 'two'}]})
E       assert 422 == 400

/home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py:89: AssertionError
=========================== short test summary info ============================
FAILED ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_malformed_json
FAILED ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_login_missing_fields
FAILED ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_malformed_json
FAILED ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_missing_fields
FAILED ../../home/lzieniew/Documents/my_local_llm_benchmarks/tasks/py-store-api/tests/test_store_api.py::test_order_non_integer_fields
5 failed, 20 passed in 0.64s
score: 20/25 (80%)
produced code
app.py
import os
import uuid
from typing import List, Optional, Dict
from fastapi import FastAPI, HTTPException, Depends, Query, status, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.responses import JSONResponse
from pydantic import BaseModel, ValidationError

# --- Models ---

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

class Product(BaseModel):
    id: int
    name: str
    price: float
    stock: int

class Order(BaseModel):
    id: int
    product_id: int
    quantity: int
    total: float
    username: str  # Internal use to track who made the order

class LoginRequest(BaseModel):
    username: str
    password: str

class OrderCreateRequest(BaseModel):
    product_id: int
    quantity: int

# --- In-Memory Database ---

users = {
    "alice": User("alice", "password123"),
    "bob": User("bob", "hunter2"),
}

products = [
    Product(id=1, name="Laptop", price=999.99, stock=10),
    Product(id=2, name="Mouse", price=25.50, stock=50),
    Product(id=3, name="Keyboard", price=75.00, stock=20),
]

orders: List[Order] = []
order_id_counter = 1

# Token mapping: token -> username
tokens: Dict[str, str] = {}

# --- App Setup ---

app = FastAPI()
security = HTTPBearer()

# --- Helpers ---

def get_current_user(auth: HTTPAuthorizationCredentials = Depends(security)) -> str:
    token = auth.credentials
    if token not in tokens:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={"error": "Invalid or missing token"}
        )
    return tokens[token]

# Custom exception handlers to ensure error responses are JSON with "error" field
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    if isinstance(exc.detail, dict):
        content = exc.detail
    else:
        content = {"error": exc.detail}
    return JSONResponse(
        status_code=exc.status_code,
        content=content
    )

@app.exception_handler(ValidationError)
async def validation_exception_handler(request: Request, exc: ValidationError):
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content={"error": str(exc.errors())}
    )

@app.exception_handler(422)
async def validation_exception_handler_422(request: Request, exc: Exception):
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content={"error": "Malformed request body or parameters"}
    )

# --- Endpoints ---

@app.post("/login")
async def login(login_data: LoginRequest):
    user = users.get(login_data.username)
    if not user or user.password != login_data.password:
        raise HTTPException(status_code=401, detail="Invalid username or password")
    
    token = str(uuid.uuid4())
    tokens[token] = login_data.username
    return {"token": token}

@app.get("/products")
async def get_products(max_price: Optional[str] = Query(None)):
    filtered_products = products
    if max_price is not None:
        try:
            mp = float(max_price)
            filtered_products = [p for p in products if p.price <= mp]
        except ValueError:
            # Not a valid number, return all products
            filtered_products = products
    
    return filtered_products

@app.get("/products/{product_id}")
async def get_product(product_id: int):
    product = next((p for p in products if p.id == product_id), None)
    if not product:
        raise HTTPException(status_code=404, detail="Product not found")
    return product

@app.post("/orders", status_code=201)
async def create_order(order_req: OrderCreateRequest, username: str = Depends(get_current_user)):
    if order_req.quantity < 1:
        raise HTTPException(status_code=400, detail="Quantity must be at least 1")

    product = next((p for p in products if p.id == order_req.product_id), None)
    if not product:
        raise HTTPException(status_code=404, detail="Product not found")
    
    if product.stock < order_req.quantity:
        raise HTTPException(status_code=409, detail="Insufficient stock")

    total = product.price * order_req.quantity
    global order_id_counter
    
    new_order = Order(
        id=order_id_counter,
        product_id=product.id,
        quantity=order_req.quantity,
        total=total,
        username=username
    )
    
    product.stock -= order_req.quantity
    orders.append(new_order)
    order_id_counter += 1
    
    return {
        "id": new_order.id,
        "product_id": new_order.product_id,
        "quantity": new_order.quantity,
        "total": new_order.total
    }

@app.get("/orders")
async def get_orders(username: str = Depends(get_current_user)):
    user_orders = [
        {
            "id": o.id,
            "product_id": o.product_id,
            "quantity": o.quantity,
            "total": o.total
        }
        for o in orders if o.username == username
    ]
    return user_orders

@app.get("/orders/{order_id}")
async def get_order(order_id: int, username: str = Depends(get_current_user)):
    order = next((o for o in orders if o.id == order_id), None)
    
    if not order or order.username != username:
        raise HTTPException(status_code=404, detail="Order not found")
    
    return {
        "id": order.id,
        "product_id": order.product_id,
        "quantity": order.quantity,
        "total": order.total
    }

# --- Main Execution ---

if __name__ == "__main__":
    import uvicorn

    host = os.getenv("HOST", "127.0.0.1")
    port = int(os.getenv("PORT", 8000))

    uvicorn.run(app, host=host, port=port)
requirements.txt
fastapi
uvicorn

rep 5 PASS

pi 378.9s · verify 0.9s · 71714 tok · responded: google/gemma-4-26b-a4b-it · transcript

verify output
.........................                                                [100%]
25 passed in 0.60s
score: 25/25 (100%)
produced code
app.py
import os
import uvicorn
from fastapi import FastAPI, Depends, HTTPException, status, Query
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, Field, validator
from typing import List, Optional, Dict
import uuid
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError

# --- Data Models ---

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

class Product:
    def __init__(self, id: int, name: str, price: float, stock: int):
        self.id = id
        self.name = name
        self.price = price
        self.stock = stock

    def to_dict(self):
        return {"id": self.id, "name": self.name, "price": self.price, "stock": self.stock}

class Order:
    def __init__(self, id: int, username: str, product_id: int, quantity: int, total: float):
        self.id = id
        self.username = username
        self.product_id = product_id
        self.quantity = quantity
        self.total = total

    def to_dict(self):
        return {"id": self.id, "product_id": self.product_id, "quantity": self.quantity, "total": self.total}

# --- API Request/Response Schemas ---

class LoginRequest(BaseModel):
    username: str
    password: str

class LoginResponse(BaseModel):
    token: str

class OrderRequest(BaseModel):
    product_id: int
    quantity: int

    @validator('quantity')
    def quantity_must_be_positive(cls, v):
        if v < 1:
            raise ValueError('quantity must be at least 1')
        return v

class OrderResponse(BaseModel):
    id: int
    product_id: int
    quantity: int
    total: float

# --- In-memory Database ---

users: Dict[str, User] = {
    "alice": User("alice", "password123"),
    "bob": User("bob", "hunter2")
}

# token -> username
active_tokens: Dict[str, str] = {}

products: Dict[int, Product] = {
    1: Product(1, "Laptop", 999.99, 10),
    2: Product(2, "Mouse", 25.50, 50),
    3: Product(3, "Keyboard", 75.00, 15)
}

orders: List[Order] = []
order_id_counter = 1

# --- App Setup ---

app = FastAPI()
security = HTTPBearer()

# --- Helpers ---

def get_current_user(auth: HTTPAuthorizationCredentials = Depends(security)) -> str:
    token = auth.credentials
    if token not in active_tokens:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={"error": "Invalid or missing token"}
        )
    return active_tokens[token]

# --- Endpoints ---

@app.post("/login")
async def login(req: LoginRequest):
    user = users.get(req.username)
    if not user or user.password != req.password:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={"error": "Invalid credentials"}
        )
    
    token = str(uuid.uuid4())
    active_tokens[token] = req.username
    return {"token": token}

@app.get("/products")
async def get_products(max_price: Optional[float] = Query(None)):
    product_list = list(products.values())
    if max_price is not None:
        product_list = [p for p in product_list if p.price <= max_price]
            
    return [p.to_dict() for p in product_list]

@app.get("/products/{product_id}")
async def get_product(product_id: int):
    product = products.get(product_id)
    if not product:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail={"error": "Product not found"}
        )
    return product.to_dict()

@app.post("/orders", status_code=status.HTTP_201_CREATED)
async def create_order(req: OrderRequest, username: str = Depends(get_current_user)):
    global order_id_counter
    
    product = products.get(req.product_id)
    if not product:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail={"error": "Product not found"}
        )
    
    if product.stock < req.quantity:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail={"error": "Not enough stock available"}
        )
    
    total = product.price * req.quantity
    new_order = Order(order_id_counter, username, product.id, req.quantity, total)
    
    # Deduct stock
    product.stock -= req.quantity
    
    orders.append(new_order)
    order_id_counter += 1
    
    return new_order.to_dict()

@app.get("/orders")
async def get_orders(username: str = Depends(get_current_user)):
    user_orders = [o.to_dict() for o in orders if o.username == username]
    return user_orders

@app.get("/orders/{order_id}")
async def get_order(order_id: int, username: str = Depends(get_current_user)):
    for o in orders:
        if o.id == order_id:
            if o.username == username:
                return o.to_dict()
            else:
                # Do not reveal existence of orders belonging to others
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail={"error": "Order not found"}
                )
    
    raise HTTPException(
        status_code=status.HTTP_404_NOT_FOUND,
        detail={"error": "Order not found"}
    )

# --- Exception Handlers ---

@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
    if isinstance(exc.detail, dict):
        content = exc.detail
    else:
        content = {"error": exc.detail}
    
    return JSONResponse(
        status_code=exc.status_code,
        content=content
    )

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={"error": "Malformed request body"}
    )

@app.exception_handler(Exception)
async def generic_exception_handler(request, exc):
    return JSONResponse(
        status_code=500,
        content={"error": str(exc)}
    )

if __name__ == "__main__":
    host = os.environ.get("HOST", "127.0.0.1")
    port = int(os.environ.get("PORT", 8000))
    uvicorn.run(app, host=host, port=port)
requirements.txt
fastapi
uvicorn