Skip to content
Open

Main #14

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
56 changes: 42 additions & 14 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
# 🐍 GitHub Copilot Instructions for FastAPI Project
# GitHub Copilot Project Instructions

## Project Overview
This is a small RESTful API built with Python and the FastAPI framework. We prioritize clean, modern Python standards and clear separation of concerns.
## Purpose
This repository is a FastAPI training project for practicing GitHub Copilot workflows. Keep changes simple, explicit, and easy to review.

## Tech Stack & Structure
* **Primary Language:** Python 3.10+
* **Framework:** FastAPI (with Uvicorn).
* **Dependency Manager:** uv (configured via pyproject.toml).
* **Data Models:** Pydantic models for all data validation and serialization.
## Stack
- Python 3.12
- FastAPI + Uvicorn
- Pydantic models
- pytest + pytest-asyncio + httpx
- uv for dependency and command execution

## Mandatory Coding Guidelines (Copilot Context)
1. **Asynchronous Code:** All route handlers and I/O-bound functions **must** be defined using `async def` and utilize `await`.
2. **Type Hints:** All function signatures (parameters and return values) **must** use explicit, descriptive type hints.
3. **Testing:** Any new endpoint or utility function **must** have a corresponding test in the `tests/` directory using `pytest` and `httpx.AsyncClient`.
4. **Model Location:** All Pydantic data models **must** be placed in a dedicated `app/models.py` file.
5. **Return Type:** API endpoints must return standard Python dicts/lists or Pydantic models, not f-strings or raw strings.
## Repository Conventions
- Main API module is `app/main.py`.
- Tests are under `tests/` and split into:
- `tests/unit/` for unit tests
- `tests/integration/` for endpoint/integration tests
- Shared test fixtures are in `tests/conftest.py`.
- Integration test files must use `@pytest.mark.integration`.

## Coding Rules
1. Prefer `async def` for route handlers and I/O-bound functions.
2. Use explicit type hints for function parameters and return values.
3. Keep API responses as structured JSON-compatible values (dict/list/Pydantic), not ad-hoc text strings for new endpoints.
4. Keep changes focused; avoid unrelated refactors.
5. Follow existing naming and formatting patterns in nearby files.

## Testing Rules
1. Add or update tests for every behavior change.
2. For endpoints, use integration tests with `httpx.AsyncClient`.
3. Cover happy path and negative/validation scenarios.
4. Keep tests deterministic; isolate mutable global state when needed.

## Run Commands
- Install and sync dependencies: `uv sync`
- Run all tests: `uv run pytest`
- Run integration tests only: `uv run pytest tests/integration -q`
- Run unit tests only: `uv run pytest tests/unit -q`
- Run app locally: `uv run uvicorn app.main:app --reload`

## Review Checklist
- Is behavior correct and test-covered?
- Are async and typing conventions followed?
- Are error paths validated?
- Are changes minimal and scoped to the request?
43 changes: 43 additions & 0 deletions .github/instructions/project.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
applyTo: "**/*.py"
---

# Project Development Instructions

## Scope
Use these instructions for general development tasks in this repository.

## Project Context
- FastAPI training project for GitHub Copilot workflows.
- Python 3.12 runtime.
- Dependency management and command execution with uv.

## Code Location
- API application: app/main.py
- Unit tests: tests/unit/
- Integration tests: tests/integration/
- Shared fixtures: tests/conftest.py

## Implementation Standards
1. Prefer async route handlers and async I/O functions.
2. Use explicit type hints on function signatures.
3. Keep changes focused and minimal.
4. Preserve existing naming and style in the touched files.

## API and Validation Standards
1. Return structured JSON-compatible values (dict, list, or Pydantic models).
2. Include clear validation and error handling paths for new behaviors.

## Testing Standards
1. Add tests for each change in behavior.
2. Use httpx.AsyncClient for endpoint integration tests.
3. Mark integration tests with @pytest.mark.integration.
4. Cover both happy path and negative scenarios.
5. Keep tests deterministic and independent.

## Common Commands
- uv sync
- uv run pytest
- uv run pytest tests/integration -q
- uv run pytest tests/unit -q
- uv run uvicorn app.main:app --reload
16 changes: 13 additions & 3 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import asyncio
from enum import Enum
from typing import List
from fastapi import FastAPI
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

class TaskStatus(str, Enum):
Expand Down Expand Up @@ -44,7 +44,7 @@ async def generate_productivity_report() -> ProductivityReport:
tasks = await fetch_all_tasks()

total_tasks = len(tasks)
completed_tasks = sum(1 for task in tasks if task.status == TaskStatus.PENDING)
completed_tasks = sum(1 for task in tasks if task.status == TaskStatus.COMPLETE)

total_hours_spent = sum(task.hours_spent for task in tasks)
completion_rate = round(completed_tasks / total_tasks, 2) if total_tasks > 0 else 0.0
Expand All @@ -71,14 +71,24 @@ async def get_all_tasks():
return await fetch_all_tasks()


@app.get("/task/{task_id}/status")
async def get_task_status(task_id: int) -> dict[str, str | int]:
task = MOCK_TASKS.get(task_id)
if task is None:
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")

return {"task_id": task_id, "status": task.status}


@app.get("/report", response_model=ProductivityReport)
async def get_productivity_report():
"""Returns the calculated productivity report."""
return await generate_productivity_report()


@app.post("/log_task")
async def log_task(task: DeveloperTask):
async def log_task(task: DeveloperTask) -> str:
"""Logs a task, assigns a new task_id on the server, and stores it in memory."""
new_id = max(MOCK_TASKS.keys()) + 1 if MOCK_TASKS else 1
task.task_id = new_id
MOCK_TASKS[new_id] = task
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@ build-backend = "hatchling.build"

[tool.uv]
default-groups = ["dev"] # Ensures dev group is installed by default during uv sync

[tool.pytest.ini_options]
markers = [
"integration: marks tests as integration tests",
]
31 changes: 31 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import AsyncGenerator, Generator

import pytest
import pytest_asyncio
from httpx import ASGITransport, AsyncClient

from app.main import app as fastapi_app


@pytest.fixture
def app():
return fastapi_app


@pytest_asyncio.fixture
async def client(app) -> AsyncGenerator[AsyncClient, None]:
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://testserver") as async_client:
yield async_client


@pytest.fixture
def db_session() -> Generator[None, None, None]:
# Placeholder fixture for future database-backed tests.
yield None


@pytest.fixture
def auth_token() -> str:
# Placeholder fixture for endpoints that require authentication.
return "test-auth-token"
Empty file added tests/integration/__init__.py
Empty file.
Loading