Python DevContainer Setup with Poetry & venv
Introduction
This section covers setting up reproducible Python development environments using Poetry for dependency management and virtual environments for isolation. Deterministic Python configurations enable consistent behavior across developer machines and CI systems.
Sections
1. Poetry Installation & Dependency Management
Poetry provides deterministic Python dependency resolution through poetry.lock files. Define project dependencies in pyproject.toml with flexible version constraints. Poetry resolves exact versions and commits them to poetry.lock.
Install Poetry in the DevContainer via devcontainer.json features or postCreateCommand. Use explicitly versioned Poetry installations to prevent drift.
2. Virtual Environment Configuration
Create Python virtual environments via python -m venv or Poetry’s built-in poetry install. Virtual environments isolate project dependencies from system-level Python packages.
Configure PYTHONPATH to prioritize container virtual environments. This prevents accidental system package usage and ensures dependency resolution consistency.
3. IDE Integration & Language Server Setup
Install pylance, pyright, or pylint via Poetry’s dev dependencies. Configure VS Code python.linting.enabled with explicit linter paths pointing to virtualenv binaries.
Use python.defaultInterpreterPath to explicitly set the virtual environment interpreter. This ensures IDE debugging and linting use the correct Python version.
4. Dependency Caching & Layer Optimization
Mount Docker named volumes to cache Poetry package caches (~/.cache/pypoetry) to accelerate rebuilds. Define postCreateCommand to run poetry install after the Dockerfile layer completes.
Use multi-stage Dockerfiles to separate build-time dependencies from runtime layers, reducing production image footprint.
Code Blocks
devcontainer.json with Python and Poetry
{
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/git:1": {}
},
"mounts": [
"source=poetry-cache,target=/root/.cache/pypoetry,type=volume"
],
"customizations": {
"vscode": {
"extensions": [
"ms-python.python@2023.2.10221011",
"ms-python.vscode-pylance@1.1.316"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true
}
}
},
"postCreateCommand": "pip install poetry==1.5.0 && poetry install"
}
Dockerfile with Poetry
FROM mcr.microsoft.com/devcontainers/python:3.11
RUN pip install --no-cache-dir poetry==1.5.0
WORKDIR /workspace
COPY pyproject.toml poetry.lock* ./
RUN poetry install --no-root
COPY . .
RUN poetry install
pyproject.toml with deterministic versions
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "DevContainer Python project"
authors = ["Team <team@example.com>"]
[tool.poetry.dependencies]
python = "^3.11"
requests = "2.31.0"
fastapi = "0.104.0"
[tool.poetry.group.dev.dependencies]
pytest = "7.4.0"
black = "23.11.0"
pylint = "3.0.0"
Common Pitfalls
- System Python usage: Installing global Python packages instead of virtualenv-specific packages causes conflicts. Always use virtualenv.
- Floating Poetry versions: Using
poetrywithout version pin causes dependency resolution drift. Always pin exact Poetry version. - Untracked poetry.lock changes: Forgetting to commit
poetry.lockto Git allows dependency resolution divergence. Always commit lock files. - IDE interpreter mismatch: Configuring VS Code Python interpreter to
/usr/bin/pythoninstead of virtualenv path causes import errors. Set explicit interpreter paths.
FAQ
How do I guarantee Poetry dependency consistency across CI and local machines?
Commit poetry.lock to Git. Use identical Poetry versions in CI and local containers. Run poetry install (not poetry update) to respect lock file.
Should I use venv or Poetry’s virtualenv?
Poetry’s virtualenv is equivalent to python -m venv. Use Poetry exclusively for dependency management—it handles virtualenv creation automatically.