Modern Python Project Setup Guide for AI Assistants
Important
For AI Assistants: This guide provides standardized instructions for helping developers scaffold modern Python projects. A plain markdown version is available for direct ingestion into AI agent contexts.
This guide provides a standardized approach to scaffolding Python projects using modern tooling. It serves as a reference for AI assistants helping developers create well-structured, maintainable Python projects.
Core Philosophy
Python project setup should be:
- Automated: Minimize manual configuration steps
- Standardized: Use PEP 621 compliant pyproject.toml
- Reproducible: Lock dependencies for consistent environments
- Quality-focused: Include linting, formatting, and testing from the start
- Isolated: Use
uv runanduvxto ensure all operations happen within project environments
Note
Tool Isolation with uv run and uvx: AI assistants should prefer uv run <command> (for dev dependencies) and uvx <command> (for installing one-off tools like pre-commit) to ensure all operations happen within the project’s isolated and locked environment, preventing reliance on globally installed tools.
Decision Tree
Follow this decision flow when helping users set up projects:
Step 1: Determine Project Type
- Is this a library/package for distribution? → Use
uv init --package - Is this an application/script/service? → Use
uv init
Step 2: Add Runtime Dependencies
- Does the project need external packages? → Use
uv add <package> - No dependencies yet? → Skip to Step 3
Step 3: Configure Development Tools (in order)
Step 4: Document Usage
- Create comprehensive README.md
- Document installation and development workflow
Standard Project Initialization
1. Create Project Structure
Tip
uv init handles the basics: Running uv init automatically creates a basic pyproject.toml (PEP 621 compliant) and a standard .gitignore file, minimizing initial manual file creation.
For applications (scripts, services, tools):
uv init project-name
cd project-nameFor packages (libraries, distributable code):
uv init project-name --package
cd project-nameTip
Use --package when creating code meant to be imported by other projects or published to PyPI.
2. Add Runtime Dependencies
# Add dependencies as needed
uv add requests pandas
# Specify version constraints when needed
uv add "django>=4.2,<5.0"3. Configure Testing with pytest
# Add pytest as development dependency
uv add --dev pytest pytest-covCreate tests/ directory:
mkdir testsNote
Modern pytest doesn’t require tests/__init__.py - the directory structure alone is sufficient for test discovery.
Add pytest configuration to pyproject.toml:
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--cov=src",
"--cov-report=term-missing",
]4. Configure Ruff for Linting and Formatting
# Add ruff as development dependency
uv add --dev ruffAdd ruff configuration to pyproject.toml:
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = [
"E501", # line length (handled by formatter)
]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"5. Setup Pre-commit Hooks
Create .pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.11
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-added-large-filesInstall hooks:
uvx pre-commit install6. Create Standard Project Files
README.md template:
# Project Name
Brief description of what the project does.
## Installation
```bash
uv sync
```
## Usage
```bash
uv run python -m project_name
```
## Development
```bash
# Run tests
uv run pytest
# Format code
uv run ruff format .
# Lint code
uv run ruff check .
```Extend .gitignore (if needed beyond what uv init provides):
# uv init already includes Python basics
# Add project-specific items:
# Testing
.pytest_cache/
.coverage
htmlcov/
# IDE (if not already present)
.vscode/
.idea/
*.swp
*.swoProject Type Patterns
CLI Tool Pattern
uv init cli-tool --package
cd cli-tool
uv add click # or typer, argparse
uv add --dev pytestAdd CLI entry point in pyproject.toml:
[project.scripts]
cli-tool = "cli_tool.main:cli"Web Application Pattern
uv init web-app
cd web-app
uv add fastapi uvicorn # or django, flask
uv add --dev pytest pytest-asyncio httpxData Science Pattern
uv init data-project
cd data-project
uv add pandas numpy matplotlib jupyter
uv add --dev pytest pytest-covAdd Jupyter configuration:
[tool.jupyter]
kernel_name = "python3"Quality Assurance Checklist
Before completing project setup, verify:
-
pyproject.tomlcontains all metadata -
uv.lockis generated -
.gitignoreexcludes virtual environments and cache files -
README.mddocuments installation and usage - Tests directory exists
- Pre-commit hooks are installed
-
uv run ruff check .passes without errors -
uv run pytestdiscovers and runs tests successfully
Common Customizations
Type Checking with mypy
uv add --dev mypy[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = trueDocumentation with mkdocs
uv add --dev mkdocs mkdocs-materialCI/CD Configuration
Example GitHub Actions workflow (.github/workflows/test.yml):
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Install dependencies
run: uv sync
- name: Run tests
run: uv run pytest
- name: Run linter
run: uv run ruff check .Anti-Patterns to Avoid
Don’t:
- Mix pip and uv in the same project
- Run tools globally instead of with
uv runoruvx - Commit
uv.lockfor libraries (do commit for applications) - Use
requirements.txtwith uv projects - Manually create virtual environments (uv handles this)
- Skip lockfiles for reproducibility
Do:
- Use
uv addfor all dependency management - Use
uv runfor dev dependencies,uvxfor one-off tools - Commit
uv.lockfor applications and CLIs - Use
[tool.uv]section for development dependencies - Let uv manage virtual environments automatically
- Pin Python versions in
pyproject.toml
Workflow Commands Reference
# Development workflow
uv run pytest # Run tests
uv run pytest --cov # Run with coverage
uv run ruff check . # Lint code
uv run ruff check --fix . # Lint and auto-fix
uv run ruff format . # Format code
# Dependency management
uv add package-name # Add runtime dependency
uv add --dev package-name # Add dev dependency
uv remove package-name # Remove dependency
uv sync # Sync environment with lockfile
uv lock # Update lockfile
# Project execution
uv run python script.py # Run script
uv run python -m module # Run module
uv run --with package cmd # Run with temporary dependency
# One-off tool execution
uvx pre-commit install # Install pre-commit hooks
uvx black . # Run black without adding to projectContext-Aware Recommendations
When helping users, consider:
- Project complexity: Simple scripts don’t need full testing infrastructure
- Team size: Larger teams benefit more from strict linting and pre-commit hooks
- Public vs private: Public packages need comprehensive docs and CI
- Performance needs: Data science projects may need specific optimizations
- Deployment target: Web apps need different structure than CLI tools
Adjust recommendations based on these factors while maintaining core best practices.
Integration with IDEs
VS Code Configuration
Create .vscode/settings.json:
{
"python.defaultInterpreterPath": ".venv/bin/python",
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests"],
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}
}PyCharm Configuration
- Set project interpreter to
.venv/bin/python - Enable pytest as test runner
- Configure Ruff as external tool
- Enable format on save