Skip to content

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 run and uvx to 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)

  1. Setup pytest for testing
  2. Setup ruff for linting/formatting
  3. Setup pre-commit hooks for automation

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-name

For packages (libraries, distributable code):

uv init project-name --package
cd project-name

Tip

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-cov

Create tests/ directory:

mkdir tests

Note

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 ruff

Add 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-files

Install hooks:

uvx pre-commit install

6. 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
*.swo

Project Type Patterns

CLI Tool Pattern

uv init cli-tool --package
cd cli-tool
uv add click  # or typer, argparse
uv add --dev pytest

Add 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 httpx

Data Science Pattern

uv init data-project
cd data-project
uv add pandas numpy matplotlib jupyter
uv add --dev pytest pytest-cov

Add Jupyter configuration:

[tool.jupyter]
kernel_name = "python3"

Quality Assurance Checklist

Before completing project setup, verify:

  • pyproject.toml contains all metadata
  • uv.lock is generated
  • .gitignore excludes virtual environments and cache files
  • README.md documents installation and usage
  • Tests directory exists
  • Pre-commit hooks are installed
  • uv run ruff check . passes without errors
  • uv run pytest discovers and runs tests successfully

Common Customizations

Type Checking with ty

uv add --dev ty

Run type checking:

uv run ty check

Configure ty in pyproject.toml:

[tool.ty.environment]
python-version = "3.11"

Documentation with mkdocs

uv add --dev mkdocs mkdocs-material

CI/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 run or uvx
  • Commit uv.lock for libraries (do commit for applications)
  • Use requirements.txt with uv projects
  • Manually create virtual environments (uv handles this)
  • Skip lockfiles for reproducibility

Do:

  • Use uv add for all dependency management
  • Use uv run for dev dependencies, uvx for one-off tools
  • Commit uv.lock for 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 project

Context-Aware Recommendations

When helping users, consider:

  1. Project complexity: Simple scripts don’t need full testing infrastructure
  2. Team size: Larger teams benefit more from strict linting and pre-commit hooks
  3. Public vs private: Public packages need comprehensive docs and CI
  4. Performance needs: Data science projects may need specific optimizations
  5. 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

  1. Set project interpreter to .venv/bin/python
  2. Enable pytest as test runner
  3. Configure Ruff as external tool
  4. Enable format on save

Learn More

Get Python tooling updates

Subscribe to the newsletter
Last updated on

Please submit corrections and feedback...