Add comprehensive Copilot instructions for repository
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
---
|
||||
applyTo: "app/**/*.py"
|
||||
---
|
||||
|
||||
# Python Backend Instructions
|
||||
|
||||
These instructions apply to all Python code in the `app/` directory.
|
||||
|
||||
## Code Style
|
||||
- Use **Black** formatter with 120 character line length
|
||||
- Use **isort** with Black profile for import organization
|
||||
- Follow **flake8** rules (ignore E203, W503 as per `.pre-commit-config.yaml`)
|
||||
- All functions must have type hints for parameters and return values
|
||||
- Use `from typing import Optional, Dict, List, Any, Union` as needed
|
||||
|
||||
## Import Order (isort with Black profile)
|
||||
```python
|
||||
# Standard library imports
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
# Third-party imports
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# Local application imports
|
||||
from app.config import settings
|
||||
from app.database import get_db
|
||||
from app.models import Document, User
|
||||
```
|
||||
|
||||
## Function Definitions
|
||||
```python
|
||||
def process_document(
|
||||
file_path: Path,
|
||||
user_id: int,
|
||||
metadata: Optional[Dict[str, Any]] = None
|
||||
) -> DocumentMetadata:
|
||||
"""
|
||||
Process a document and extract metadata.
|
||||
|
||||
Args:
|
||||
file_path: Path to the document file
|
||||
user_id: ID of the user uploading the document
|
||||
metadata: Optional additional metadata
|
||||
|
||||
Returns:
|
||||
DocumentMetadata object with extracted information
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If file doesn't exist
|
||||
ProcessingError: If processing fails
|
||||
"""
|
||||
pass
|
||||
```
|
||||
|
||||
## FastAPI Endpoints
|
||||
- Use dependency injection for DB sessions and auth
|
||||
- Return Pydantic models for automatic validation
|
||||
- Use proper status codes from `fastapi.status`
|
||||
- Add detailed docstrings for OpenAPI docs
|
||||
```python
|
||||
from fastapi import APIRouter, Depends, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
router = APIRouter(prefix="/api/documents", tags=["documents"])
|
||||
|
||||
@router.post("/", status_code=status.HTTP_201_CREATED)
|
||||
async def create_document(
|
||||
file: UploadFile,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> DocumentResponse:
|
||||
"""Create and process a new document."""
|
||||
pass
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
- Use custom exceptions from the application
|
||||
- Log errors with context using `logging.getLogger(__name__)`
|
||||
- Return user-friendly error messages
|
||||
- Never expose internal details in production errors
|
||||
```python
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
result = process_file(file_path)
|
||||
except FileNotFoundError:
|
||||
logger.error(f"File not found: {file_path}")
|
||||
raise HTTPException(status_code=404, detail="File not found")
|
||||
except Exception as e:
|
||||
logger.exception(f"Error processing file: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Processing failed")
|
||||
```
|
||||
|
||||
## Database Operations
|
||||
- Use SQLAlchemy ORM, never raw SQL with user input
|
||||
- Use `get_db()` dependency for sessions
|
||||
- Always commit in try/except blocks
|
||||
```python
|
||||
from sqlalchemy.orm import Session
|
||||
from app.database import get_db
|
||||
|
||||
def create_document(db: Session, document_data: dict) -> Document:
|
||||
"""Create a new document in the database."""
|
||||
db_document = Document(**document_data)
|
||||
try:
|
||||
db.add(db_document)
|
||||
db.commit()
|
||||
db.refresh(db_document)
|
||||
return db_document
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
raise
|
||||
```
|
||||
|
||||
## Celery Tasks
|
||||
- Define in `app/tasks/` directory
|
||||
- Use descriptive names: `module.action`
|
||||
- Set retry policies
|
||||
- Log progress and errors
|
||||
```python
|
||||
from celery import shared_task
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@shared_task(bind=True, max_retries=3)
|
||||
def process_ocr(self, document_id: int) -> Dict[str, Any]:
|
||||
"""Process OCR for a document."""
|
||||
try:
|
||||
# Processing logic
|
||||
logger.info(f"Processing OCR for document {document_id}")
|
||||
return {"status": "success"}
|
||||
except Exception as exc:
|
||||
logger.exception(f"OCR processing failed for {document_id}")
|
||||
raise self.retry(exc=exc, countdown=60)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
- All settings in `app/config.py` using Pydantic Settings
|
||||
- Use environment variables, never hardcode values
|
||||
- Provide defaults when sensible
|
||||
```python
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
class Settings(BaseSettings):
|
||||
openai_api_key: str
|
||||
max_file_size: int = 10485760 # 10MB default
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
```
|
||||
|
||||
## Security
|
||||
- Never commit secrets
|
||||
- Validate all user inputs
|
||||
- Use parameterized queries
|
||||
- Sanitize file paths
|
||||
- Check file permissions
|
||||
- Review SECURITY_AUDIT.md for guidelines
|
||||
Reference in New Issue
Block a user