KCH / src /chapters /ch01-project-structure.qmd
bsamadi's picture
Update to pixi env
c032460
# Modern Python Project Structure
## Learning Objectives
- Understand modern Python project layouts
- Learn about `pyproject.toml` and `pixi.toml` configuration files
- Set up proper directory structure for CLI applications
- Implement version control best practices
## Project Layout Options
There are two main approaches to organizing Python projects:
### Flat Layout
```
my-cli/
β”œβ”€β”€ my_cli/
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ cli.py
β”‚ └── utils.py
β”œβ”€β”€ tests/
β”œβ”€β”€ pyproject.toml
└── README.md
```
### Src Layout (Recommended)
```
my-cli/
β”œβ”€β”€ src/
β”‚ └── my_cli/
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ cli.py
β”‚ └── utils.py
β”œβ”€β”€ tests/
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ pixi.toml
└── README.md
```
**Why src layout?**
- Prevents accidental imports from development directory
- Clearer separation between source and other files
- Better for testing and packaging
## Essential Configuration Files
### pyproject.toml
The modern standard for Python project metadata:
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-cli-tool"
version = "0.1.0"
description = "An AI-powered CLI tool"
authors = [{name = "Your Name", email = "you@example.com"}]
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"typer>=0.9",
"rich>=13.0",
]
[project.scripts]
my-cli = "my_cli.cli:app"
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.mypy]
python_version = "3.11"
strict = true
```
### pixi.toml
Pixi-specific configuration for environment management:
```toml
[project]
name = "my-cli-tool"
version = "0.1.0"
description = "An AI-powered CLI tool"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-64", "win-64"]
[dependencies]
python = ">=3.11"
typer = ">=0.9"
rich = ">=13.0"
[feature.dev.dependencies]
pytest = "*"
ruff = "*"
mypy = "*"
black = "*"
[environments]
default = []
dev = ["dev"]
[tasks]
start = "python -m my_cli.cli"
test = "pytest tests/"
lint = "ruff check src/"
format = "black src/ tests/"
```
## Complete Project Structure
Here's a complete, production-ready project structure:
```
my-cli-tool/
β”œβ”€β”€ .git/ # Git repository
β”œβ”€β”€ .gitignore # Git ignore rules
β”œβ”€β”€ .vscode/ # VS Code settings
β”‚ └── settings.json
β”œβ”€β”€ src/
β”‚ └── my_cli/
β”‚ β”œβ”€β”€ __init__.py # Package initialization
β”‚ β”œβ”€β”€ cli.py # Main CLI entry point
β”‚ β”œβ”€β”€ commands/ # Command modules
β”‚ β”‚ β”œβ”€β”€ __init__.py
β”‚ β”‚ β”œβ”€β”€ organize.py
β”‚ β”‚ └── stats.py
β”‚ β”œβ”€β”€ core/ # Core functionality
β”‚ β”‚ β”œβ”€β”€ __init__.py
β”‚ β”‚ └── processor.py
β”‚ └── utils/ # Utility functions
β”‚ β”œβ”€β”€ __init__.py
β”‚ └── helpers.py
β”œβ”€β”€ tests/
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ conftest.py # Pytest configuration
β”‚ β”œβ”€β”€ test_cli.py
β”‚ └── test_core.py
β”œβ”€β”€ docs/ # Documentation
β”‚ └── README.md
β”œβ”€β”€ .gitignore
β”œβ”€β”€ pyproject.toml # Python project config
β”œβ”€β”€ pixi.toml # Pixi environment config
β”œβ”€β”€ pixi.lock # Locked dependencies
β”œβ”€β”€ LICENSE # License file
└── README.md # Project documentation
```
## Creating the Structure
Use this script to create the structure:
```bash
#!/bin/bash
# create-project.sh
PROJECT_NAME="my-cli-tool"
PACKAGE_NAME="my_cli"
# Create directories
mkdir -p $PROJECT_NAME/{src/$PACKAGE_NAME/{commands,core,utils},tests,docs,.vscode}
# Create __init__.py files
touch $PROJECT_NAME/src/$PACKAGE_NAME/__init__.py
touch $PROJECT_NAME/src/$PACKAGE_NAME/commands/__init__.py
touch $PROJECT_NAME/src/$PACKAGE_NAME/core/__init__.py
touch $PROJECT_NAME/src/$PACKAGE_NAME/utils/__init__.py
touch $PROJECT_NAME/tests/__init__.py
# Create main files
touch $PROJECT_NAME/src/$PACKAGE_NAME/cli.py
touch $PROJECT_NAME/README.md
touch $PROJECT_NAME/LICENSE
echo "Project structure created!"
```
Or use pixi to create it:
```bash
# Initialize with pixi
pixi init my-cli-tool
cd my-cli-tool
# Add Python and dependencies
pixi add python typer rich
# Create src layout
mkdir -p src/my_cli/{commands,core,utils}
touch src/my_cli/__init__.py
touch src/my_cli/cli.py
# Create tests
mkdir tests
touch tests/__init__.py
```
## .gitignore
Essential patterns for Python projects:
```gitignore
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Pixi
.pixi/
pixi.lock
# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
# Testing
.pytest_cache/
.coverage
htmlcov/
# OS
.DS_Store
Thumbs.db
```
## Version Control Setup
Initialize Git and make your first commit:
```bash
# Initialize repository
git init
# Create .gitignore (use content above)
# Use Copilot: "Generate a comprehensive .gitignore for Python projects"
# Add files
git add .
# First commit
git commit -m "Initial project structure"
# Create GitHub repository (optional)
gh repo create my-cli-tool --public --source=. --remote=origin
git push -u origin main
```
## Package Initialization
### src/my_cli/__init__.py
```python
"""My CLI Tool - An AI-powered command-line application."""
__version__ = "0.1.0"
__author__ = "Your Name"
__email__ = "you@example.com"
# Export main components
from .cli import app
__all__ = ["app"]
```
## Best Practices
1. **Use src layout**: Prevents import issues and improves testing
2. **Lock dependencies**: Commit `pixi.lock` for reproducibility
3. **Separate concerns**: Use subdirectories for commands, core logic, and utilities
4. **Write tests early**: Create test files alongside implementation
5. **Document as you go**: Update README with each feature
6. **Use type hints**: Enable better IDE support and catch errors early
## Using Copilot for Project Setup
Ask Copilot to help with:
```python
# In your IDE, write comments like:
# "Create a pyproject.toml for a CLI tool with typer and rich dependencies"
# "Generate a comprehensive .gitignore for a Python project"
# "Create a README template for a CLI application"
```
## Next Steps
With your project structure in place, you're ready to start building your CLI application. In the next chapter, we'll use Typer to create powerful command-line interfaces.
## Resources
- [Python Packaging Guide](https://packaging.python.org/)
- [Pixi Project Configuration](https://pixi.sh/latest/reference/project_configuration/)
- [PEP 518 - pyproject.toml](https://peps.python.org/pep-0518/)