diff --git a/.devcontainer/Dockerfile.dev b/.devcontainer/Dockerfile.dev new file mode 100644 index 0000000..5bce3e0 --- /dev/null +++ b/.devcontainer/Dockerfile.dev @@ -0,0 +1,27 @@ +ARG UV_VERSION=0.8.13 + +FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv + +FROM mcr.microsoft.com/devcontainers/base:bookworm + +COPY --from=uv /uv /uvx /bin/ + +# Python environment variables for development +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PYTHONIOENCODING=utf-8 \ + PIP_NO_CACHE_DIR=1 \ + PIP_DISABLE_PIP_VERSION_CHECK=1 \ + UV_NO_CACHE=1 \ + UV_PROJECT_ENVIRONMENT=/app/.venv \ + LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 + +USER vscode + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +WORKDIR /app + +HEALTHCHECK --interval=60s --timeout=5s --start-period=60s --retries=3 \ + CMD test -d /app && whoami || exit 1 diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 0000000..0fb4953 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,120 @@ +# Development Container + +This project uses a [Development Container](https://containers.dev/) to provide a consistent development environment. + +## Getting Started + +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) +2. Install [VS Code](https://code.visualstudio.com/) and the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) +3. Open this folder in VS Code +4. When prompted, click "Reopen in Container" (or run command: `Dev Containers: Reopen in Container`) + +## Local Customization + +To customize your local development environment without modifying the committed configuration, create a `.devcontainer/devcontainer.local.json` file (this file is gitignored). + +### Example: Add Additional VS Code Extensions + +```json +{ + "customizations": { + "vscode": { + "extensions": [ + "esbenp.prettier-vscode", + "usernamehw.errorlens" + ] + } + } +} +``` + +### Example: Mount Additional Volumes + +```json +{ + "mounts": [ + "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached" + ] +} +``` + +### Example: Override or Add Environment Variables + +The container sets several Python-related environment variables by default (see `Dockerfile.dev`). You can override them or add new ones using `remoteEnv`: + +```json +{ + "remoteEnv": { + "PYTHONUNBUFFERED": "0", + "DEBUG": "1", + "LOG_LEVEL": "DEBUG" + } +} +``` + +See `devcontainer.local.json.example` for a complete list of default environment variables that can be overridden. + +Alternatively, create a `.devcontainer/.env` file (also gitignored): +```bash +DEBUG=1 +LOG_LEVEL=DEBUG +``` + +And reference it in `devcontainer.local.json`: +```json +{ + "runArgs": ["--env-file", ".devcontainer/.env"] +} +``` + +### Example: Forward Additional Ports + +```json +{ + "forwardPorts": [8080, 3000] +} +``` + +## How It Works + +The Dev Container will: +- Build from `Dockerfile.dev` +- Mount your workspace to `/app` +- Install Git and GitHub CLI features +- Run `uv sync --all-groups` to create a virtual environment at `/app/.venv` +- Configure VS Code to use the virtual environment's Python interpreter +- Set up bash as the default terminal + +### Default Environment Variables + +The following Python-related environment variables are set in the container: + +- **`PYTHONUNBUFFERED=1`** - Ensures real-time output in logs +- **`PYTHONDONTWRITEBYTECODE=1`** - Prevents `.pyc` file creation +- **`PYTHONIOENCODING=utf-8`** - Ensures UTF-8 encoding for I/O +- **`PIP_NO_CACHE_DIR=1`** - Disables pip caching to reduce container size +- **`PIP_DISABLE_PIP_VERSION_CHECK=1`** - Suppresses pip update warnings +- **`UV_NO_CACHE=1`** - Disables uv caching +- **`UV_PROJECT_ENVIRONMENT=/app/.venv`** - Sets the virtual environment location for uv +- **`LANG=C.UTF-8`** - Sets locale for proper Unicode handling +- **`LC_ALL=C.UTF-8`** - Sets all locale categories to UTF-8 + +These can be overridden in `devcontainer.local.json` using the `remoteEnv` property. + +### Virtual Environment + +The project uses `uv` to manage dependencies. When the container is created: +1. `uv sync --all-groups` is automatically run to create a virtual environment at `/app/.venv` +2. VS Code is configured to use `/app/.venv/bin/python` as the Python interpreter +3. All dependencies from `pyproject.toml` (including dev groups) are installed + +To manually update dependencies, run: +```bash +uv sync --all-groups +``` + +## Rebuilding the Container + +If you modify the Dockerfile or devcontainer configuration: +1. Run command: `Dev Containers: Rebuild Container` +2. Or run: `Dev Containers: Rebuild Container Without Cache` for a clean build diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a686774 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +{ + // To customize this for your local environment without committing changes, + // create a .devcontainer/devcontainer.local.json file (it's gitignored). + // See .devcontainer/README.md for examples. + "name": "toon-python (devcontainer)", + "build": { + "dockerfile": "Dockerfile.dev", + "context": ".." + }, + "workspaceFolder": "/app", + "mounts": [ + "source=${localWorkspaceFolder},target=/app,type=bind,consistency=cached" + ], + "features": { + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "remoteEnv": { + // Python environment variables (can be overridden in devcontainer.local.json) + // These supplement the ENV vars set in Dockerfile.dev + }, + "postCreateCommand": "uv sync --all-groups", + "customizations": { + "vscode": { + "settings": { + "python.defaultInterpreterPath": "/app/.venv/bin/python" + } + } + } +} diff --git a/.devcontainer/devcontainer.local.json.example b/.devcontainer/devcontainer.local.json.example new file mode 100644 index 0000000..65e0d3f --- /dev/null +++ b/.devcontainer/devcontainer.local.json.example @@ -0,0 +1,32 @@ +{ + // Example local devcontainer configuration + // Copy this to devcontainer.local.json and customize as needed + // This file is gitignored and won't be committed + + "remoteEnv": { + // Override Python environment variables + // Uncomment and modify any of these to override defaults from Dockerfile.dev: + + // "PYTHONUNBUFFERED": "0", + // "PYTHONDONTWRITEBYTECODE": "0", + // "PYTHONIOENCODING": "utf-8", + // "PIP_NO_CACHE_DIR": "0", + // "PIP_DISABLE_PIP_VERSION_CHECK": "0", + // "UV_NO_CACHE": "0", + // "UV_PROJECT_ENVIRONMENT": "/custom/path/.venv", + // "LANG": "en_US.UTF-8", + // "LC_ALL": "en_US.UTF-8", + + // Add custom environment variables for local development: + // "DEBUG": "1", + // "LOG_LEVEL": "DEBUG" + }, + + // You can also override other devcontainer settings: + // "features": {}, + // "customizations": { + // "vscode": { + // "extensions": [] + // } + // } +} diff --git a/.gitignore b/.gitignore index e14d4f7..0575f02 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ venv/ ENV/ env.bak/ venv.bak/ +.python-version # IDEs .vscode/ @@ -74,6 +75,10 @@ venv.bak/ .claude/ CLAUDE.md +# DevContainer local overrides +.devcontainer/devcontainer.local.json +.devcontainer/.env + # macOS .DS_Store .AppleDouble diff --git a/.python-version b/.python-version deleted file mode 100644 index 6324d40..0000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.14