| name | python |
| description | Python coding standards, best practices, type hints, and testing patterns with uv for package management. Use when writing or reviewing Python code, implementing tests, setting up Python projects, managing dependencies with uv, working with virtual environments, adding type hints, writing pytest tests, or discussing Python language features and best practices. |
Python
- Use the latest Python language features appropriate for the project's minimum supported version.
- Always work within a virtual environment (never install packages globally).
- Use type hints for all function signatures and complex variables.
- Write tests using pytest with clear, descriptive test names.
- Follow PEP 8 conventions and use Google-style docstrings.
Quick Start
For a new Python project:
# 1. Create virtual environment
uv venv
# 2. Activate it (optional, uv commands work without activation)
source .venv/bin/activate # macOS/Linux
# 3. Add dependencies
uv add <package-name>
# 4. Run your script
uv run script.py
Package Management
- Use
uvfor dependency management and package execution with virtual environments. - Always ensure a virtual environment exists before running Python code.
Virtual Environment Workflow
Before any Python work, ensure a virtual environment exists:
# Check if .venv exists
if [ ! -d ".venv" ]; then
echo "Creating virtual environment..."
uv venv
fi
Complete workflow example:
# 1. Create virtual environment (one-time setup)
uv venv
# Output: Using CPython 3.12.0
# Creating virtual environment at: .venv
# 2. uv automatically detects and uses .venv for all operations
# No activation needed for uv commands!
# 3. Add a dependency
uv add requests
# Output: Resolved 5 packages in 142ms
# Installed 5 packages in 23ms
# 4. Run your script (automatically uses .venv)
uv run script.py
# 5. Install dev dependencies
uv add --dev pytest ruff mypy
# 6. Sync environment with lock file
uv sync
Manual activation (optional, for running Python directly):
# macOS/Linux (bash/zsh)
source .venv/bin/activate
# Windows (Command Prompt)
.venv\Scripts\activate
# Windows (PowerShell)
.venv\Scripts\Activate.ps1
# Fish shell
source .venv/bin/activate.fish
# Deactivate when done
deactivate
Key commands:
uv run <script>- Run script in virtual environmentuv add <package>- Add production dependencyuv add --dev <package>- Add development dependencyuv pip install <package>- Direct pip-compatible installuv sync- Sync environment with lock fileuv pip list- List installed packagesuv pip freeze- Export requirements
Troubleshooting:
- If uv doesn't detect
.venv, ensure you're in the project root - Use
uv venv --python 3.11to specify Python version - Run
uv venv --helpfor advanced options
Documentation
When users ask about Python standard library modules, use WebFetch to get the latest official documentation from docs.python.org.
Example:
- For
asyncio:https://docs.python.org/3/library/asyncio.html - For
typing:https://docs.python.org/3/library/typing.html - For
pathlib:https://docs.python.org/3/library/pathlib.html
Pattern: https://docs.python.org/3/library/<module>.html
Use Google-style docstrings for all functions, classes, and modules. Follow this format:
def function_name(arg1: Type, arg2: Type) -> ReturnType:
"""One-line summary of what the function does.
More detailed description if needed, explaining the purpose,
behavior, and any important notes.
Args:
arg1: Description of arg1, including type and meaning.
arg2: Description of arg2, including type and meaning.
Returns:
Description of the return value, including type.
Raises:
ExceptionType: Description of when this exception is raised.
AnotherException: Another exception description.
Examples:
>>> function_name('example', 42)
'result'
"""
For classes:
class MyClass:
"""Brief description of the class.
Longer description if needed.
Attributes:
attr1: Description of attr1.
attr2: Description of attr2.
"""
Type Hints
- Always use type hints for function signatures, class attributes, and variables where the type is not immediately obvious.
- Avoid using
Anytype. Use specific types,TypeVar, or protocols instead. - Avoid using
# type: ignorecomments except in rare cases, mainly in test code. - Use
from __future__ import annotationsfor forward references and cleaner type hints. - Prefer
list[T],dict[K, V],set[T],tuple[T, ...]overtyping.List,typing.Dict, etc. (Python 3.9+).
Example:
from __future__ import annotations
def process_items(items: list[str], max_count: int | None = None) -> dict[str, int]:
"""Process items and return a count dictionary."""
result: dict[str, int] = {}
for item in items[:max_count]:
result[item] = result.get(item, 0) + 1
return result
Tests
Write parametrized tests using pytest:
import pytest
@pytest.mark.parametrize(
("input_value", "expected"),
[
("hello", "HELLO"),
("world", "WORLD"),
("", ""),
],
)
def test_uppercase(input_value: str, expected: str) -> None:
assert my_function(input_value) == expected
- Use descriptive parameter names in test cases.
- Type hint test functions with
-> None. - Group related tests in classes when appropriate.
- Use fixtures for shared setup and teardown.
Code Style
- Follow PEP 8 conventions.
- Use f-strings for string formatting.
- Maximum line length: 88 characters (Black default).
- Use trailing commas in multi-line structures.
- Prefer explicit over implicit ("Explicit is better than implicit").
Common Patterns
Project Initialization
# Start a new Python project
mkdir my-project && cd my-project
uv venv
uv add requests pytest ruff mypy
Dependency Management
# Add packages
uv add pandas numpy # Production dependencies
uv add --dev black pytest-cov # Development dependencies
# Update packages
uv sync --upgrade
# Remove a package
uv remove package-name
Type-Checked Function
from __future__ import annotations
from pathlib import Path
def read_config(path: Path) -> dict[str, str | int]:
"""Read configuration from a file.
Args:
path: Path to the configuration file.
Returns:
Dictionary containing configuration key-value pairs.
Raises:
FileNotFoundError: If the configuration file doesn't exist.
ValueError: If the file contains invalid configuration.
"""
if not path.exists():
raise FileNotFoundError(f"Config file not found: {path}")
# Implementation here
return {}
Pytest Test Structure
import pytest
from pathlib import Path
from mymodule import read_config
@pytest.fixture
def config_file(tmp_path: Path) -> Path:
"""Create a temporary config file for testing."""
config = tmp_path / "config.ini"
config.write_text("key=value")
return config
@pytest.mark.parametrize(
("input_value", "expected"),
[
("hello", "HELLO"),
("world", "WORLD"),
("", ""),
("Hello World!", "HELLO WORLD!"),
],
ids=["simple", "another", "empty", "with-punctuation"],
)
def test_uppercase(input_value: str, expected: str) -> None:
"""Test uppercase conversion with various inputs."""
assert my_function(input_value) == expected
def test_read_config_success(config_file: Path) -> None:
"""Test successful configuration reading."""
result = read_config(config_file)
assert isinstance(result, dict)
def test_read_config_missing_file() -> None:
"""Test error handling for missing configuration file."""
with pytest.raises(FileNotFoundError, match="Config file not found"):
read_config(Path("/nonexistent/config.ini"))
Context Manager Pattern
from typing import Generator
from contextlib import contextmanager
@contextmanager
def database_connection(url: str) -> Generator[Connection, None, None]:
"""Manage database connection lifecycle.
Args:
url: Database connection URL.
Yields:
Active database connection.
Examples:
>>> with database_connection("sqlite:///db.sqlite") as conn:
... conn.execute("SELECT * FROM users")
"""
conn = create_connection(url)
try:
yield conn
finally:
conn.close()