# AGENTS.md - File Server Project ## Project Overview This is a FastAPI-based file server that serves files from a directory or ZIP archive using hashed paths. The server indexes files and serves them via random access or by hash lookup. ## Language & Runtime - **Language**: Python 3.13 - **Framework**: FastAPI 0.128.0+ - **Server**: Uvicorn 0.40.0+ ## Build, Lint, and Test Commands ### Running the Server ```bash # Run with a directory python main.py /path/to/files # Run with a ZIP archive python main.py /path/to/archive.zip ``` ### Testing No test framework is currently configured. To add tests, install pytest: ```bash pip install pytest ``` Run all tests: ```bash pytest ``` Run a single test: ```bash pytest path/to/test_file.py::TestClass::test_method pytest -k "test_name_pattern" ``` ### Linting No linting tool is currently configured. Recommended tools: ```bash # Install ruff (fast linter/formatter) pip install ruff # Run linting ruff check . # Auto-fix issues ruff check --fix . # Format code ruff format . ``` Alternatively, using pylint: ```bash pip install pylint pylint main.py ``` ### Type Checking ```bash # Install mypy pip install mypy # Run type checking mypy main.py ``` ## Code Style Guidelines ### Imports - Standard library imports first, then third-party, then local - Group imports by type: stdlib, third-party, local - Use absolute imports for local modules - Example: ```python import os import sys from pathlib import Path from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse, StreamingResponse from mymodule import MyClass ``` ### Formatting - Use 4 spaces for indentation (no tabs) - Maximum line length: 100 characters - Use blank lines to separate logical sections (2 blank lines between top-level definitions) - One blank line between method definitions within a class ### Types - Use type hints for all function arguments and return values - Use Python 3.13+ typing features where appropriate - Example: ```python def process_file(path: str) -> bytes: ... class FileIndexer: def __init__(self, path: str) -> None: ... ``` ### Naming Conventions - **Classes**: `PascalCase` (e.g., `FileIndexer`, `ZipFileIndexer`) - **Functions/variables**: `snake_case` (e.g., `get_file_by_hash`, `file_mapping`) - **Constants**: `UPPER_SNAKE_CASE` (e.g., `INDEXER_MAP`) - **Private methods/attributes**: Prefix with underscore (e.g., `_index`, `_salt`) - Use descriptive, full words for names (avoid abbreviations except well-known ones) ### Error Handling - Use exceptions for exceptional cases, not flow control - Raise `HTTPException` for HTTP-level errors in FastAPI endpoints - Provide meaningful error messages - Example: ```python if not indexer.file_mapping: raise HTTPException(status_code=404, detail="No files indexed") if file_hash not in self.file_mapping: return None ``` ### Async/Await - Use `async def` for FastAPI endpoint handlers - Use regular functions for synchronous operations (file I/O, hashing) - Do not mix sync and async improperly ### File Operations - Use `pathlib.Path` for path manipulations - Use context managers (`with` statements) for file operations - Handle both directory and archive (ZIP) file sources ### Documentation - Use docstrings for public classes and functions - Follow Google-style docstring format: ```python def get_file_by_hash(file_hash: str) -> str | None: """Get filename by hash. Args: file_hash: The hash identifier for the file. Returns: The filename if found, None otherwise. """ ``` ### Best Practices - Keep functions small and focused (single responsibility) - Use properties for computed attributes with caching - Avoid global state where possible; use dependency injection - Use dataclasses or attrs for simple data containers - Follow PEP 8 style guidelines ## Project Structure ``` /projects/file_server/ ├── main.py # Main application entry point ├── pyproject.toml # Project configuration ├── .python-version # Python version specification └── README.md # Project documentation (currently empty) ``` ## Common Tasks ### Adding a New Endpoint 1. Add the route handler in `main.py` 2. Use appropriate HTTP method decorator (`@app.get`, `@app.post`, etc.) 3. Add type hints and docstrings 4. Handle errors with `HTTPException` ### Adding a New File Indexer 1. Create a new class inheriting from `FileIndexer` 2. Override the `_index` method to populate `self.file_mapping` 3. Implement `get_file_by_hash` and `get_filename_by_hash` 4. Register in `INDEXER_MAP` dictionary ### Running the Server in Development ```bash python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000 ```