Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:30:04 +08:00
commit 833eac73ea
20 changed files with 2939 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
{
"name": "pythonic",
"description": "Python project setup and development workflows following modern best practices with uv, ruff, pytest, and FastAPI",
"version": "1.0.0",
"author": {
"name": "Joseph Platta"
},
"skills": [
"./skills"
],
"agents": [
"./agents"
],
"commands": [
"./commands"
],
"hooks": [
"./hooks"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# pythonic
Python project setup and development workflows following modern best practices with uv, ruff, pytest, and FastAPI

View File

@@ -0,0 +1,376 @@
---
description: Orchestrate complete Python project setup with modern tooling and best practices
---
# Python Project Setup Agent
This agent handles the end-to-end setup of a new Python project following modern best practices with uv, ruff, pytest, and comprehensive project structure.
## When to Invoke
Automatically invoke this agent when:
- User requests to "create a new Python project"
- User asks to "initialize a Python project"
- User mentions "start a Python project from scratch"
- User requests "Python project setup" or "Python scaffolding"
## Agent Capabilities
This agent orchestrates the complete project setup process by:
1. Gathering project requirements from the user
2. Initializing the project structure
3. Configuring modern tooling (uv, ruff, pytest, mypy)
4. Setting up development environment
5. Creating documentation and configuration files
6. Verifying the setup is functional
## Tools Available
This agent has access to all standard Claude Code tools:
- **Bash**: For running commands (uv, git, etc.)
- **Write**: For creating configuration files
- **Read**: For verifying files
- **Edit**: For modifying generated files
- **Glob/Grep**: For searching when needed
## Skills to Leverage
The agent should utilize these plugin skills:
- `python-project-setup`: Project structure and initialization
- `python-code-quality`: Ruff and mypy configuration
- `python-testing`: Pytest setup and test creation
## Setup Process
### Phase 1: Discovery and Planning
1. **Ask the User Questions**
- Project name
- Python version (default: latest stable 3.11+)
- Project type (library, CLI application, web API, data science)
- Whether to include FastAPI for web APIs
- Whether to include additional tools (mkdocs, docker, etc.)
2. **Validate Requirements**
- Check if uv is installed
- Check if pyenv is installed (optional but recommended)
- Check if git is initialized
### Phase 2: Project Initialization
1. **Create Project Structure**
```bash
uv init <project-name>
cd <project-name>
```
2. **Set Python Version**
- Create `.python-version` file with specified version
- Verify Python version is available
3. **Initialize Git (if not already)**
```bash
git init
```
### Phase 3: Directory Structure
Create the following directories:
```
<project-name>/
├── .vscode/
├── src/<project_name>/
│ ├── __init__.py
│ ├── main.py
│ ├── models/
│ ├── services/
│ └── utils/
├── tests/
│ ├── __init__.py
│ └── conftest.py
├── docs/
└── .github/
└── workflows/
```
### Phase 4: Dependencies
1. **Install Core Dependencies**
```bash
# Development tools
uv add --dev pytest
uv add --dev pytest-cov
uv add --dev ruff
uv add --dev mypy
# Runtime dependencies
uv add pydantic
```
2. **Install Optional Dependencies** (based on project type)
- For web APIs: `uv add fastapi uvicorn[standard]`
- For documentation: `uv add --dev mkdocs mkdocs-material`
- For async: `uv add --dev pytest-asyncio`
### Phase 5: Configuration Files
1. **Create `pyproject.toml`**
- Use template from `python-project-setup` skill
- Configure ruff linting and formatting rules
- Configure pytest settings
- Configure mypy type checking
- Add project metadata
2. **Create `.gitignore`**
- Use template from `python-project-setup` skill
- Include Python-specific patterns
3. **Create `.vscode/settings.json`**
- Use template from `python-project-setup` skill
- Configure Python interpreter path
- Enable ruff for linting and formatting
- Configure pytest integration
4. **Create `README.md`**
- Use template from `python-project-setup` skill
- Include project description, installation, usage
- Add development setup instructions
### Phase 6: Initial Code
1. **Create Main Module** (`src/<project_name>/main.py`)
```python
"""Main module for <project-name>."""
def main() -> None:
"""Main entry point."""
print("Hello from <project-name>!")
if __name__ == "__main__":
main()
```
2. **Create Initial Test** (`tests/test_main.py`)
```python
"""Tests for main module."""
from <project_name>.main import main
def test_main():
"""Test main function runs without error."""
main() # Should not raise
```
### Phase 7: CI/CD Setup
1. **Create GitHub Actions Workflow** (`.github/workflows/test.yml`)
```yaml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Set up Python
run: uv python install ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync
- name: Run ruff
run: uv run ruff check .
- name: Run mypy
run: uv run mypy src
- name: Run tests
run: uv run pytest --cov
```
### Phase 8: Verification
1. **Sync Dependencies**
```bash
uv sync
```
2. **Run Quality Checks**
```bash
uv run ruff check .
uv run ruff format .
uv run mypy src
```
3. **Run Tests**
```bash
uv run pytest -v
```
4. **Verify Structure**
- Check all directories exist
- Check all configuration files are present
- Check imports work correctly
### Phase 9: Summary
Provide the user with:
1. **What was created**: List of directories and files
2. **Next steps**: How to start developing
3. **Useful commands**:
```bash
# Run the application
uv run python -m <project_name>
# Run tests
uv run pytest
# Run linting
uv run ruff check .
# Format code
uv run ruff format .
# Type check
uv run mypy src
# Add dependencies
uv add <package>
uv add --dev <dev-package>
```
## Error Handling
### Missing uv
If uv is not installed:
```bash
# Provide installation instructions
curl -LsSf https://astral.sh/uv/install.sh | sh
```
### Permission Issues
If directory creation fails, check permissions and suggest:
```bash
# Try with appropriate permissions
mkdir -p <directory>
```
### Version Conflicts
If Python version is not available:
```bash
# Install with pyenv
pyenv install <version>
```
## Success Criteria
The setup is complete when:
- [ ] All directories and files are created
- [ ] Dependencies are installed successfully
- [ ] Linting passes without errors
- [ ] Type checking passes without errors
- [ ] All tests pass
- [ ] Git repository is initialized
- [ ] README provides clear documentation
## Project Type Variations
### Web API (FastAPI)
Additional setup:
- Install FastAPI and uvicorn
- Create `src/<project_name>/api/` directory
- Create `src/<project_name>/api/main.py` with sample endpoint
- Add API documentation to README
### CLI Application
Additional setup:
- Add entry point to `pyproject.toml` `[project.scripts]`
- Create CLI module with argparse or Click
- Add usage examples to README
### Library
Additional setup:
- Focus on clean API design
- Comprehensive docstrings
- More extensive testing
- Consider adding type stubs
### Data Science
Additional setup:
- Add `notebooks/` directory
- Install Jupyter: `uv add --dev jupyter`
- Install common packages: pandas, numpy, matplotlib
- Create sample notebook
## Post-Setup Recommendations
1. **Set up pre-commit hooks** (optional)
```bash
uv add --dev pre-commit
# Create .pre-commit-config.yaml
```
2. **Configure Dependabot**
- Create `.github/dependabot.yml`
3. **Add more documentation**
- API documentation
- Architecture decisions
- Contributing guidelines
4. **Consider Docker** (if needed)
- Create Dockerfile
- Create docker-compose.yml
## Example Interaction
```
User: I want to create a new Python project called "weather-api" for a FastAPI application
Agent:
I'll help you set up a new Python project with FastAPI. Let me gather some information:
- Project name: weather-api
- Project type: Web API (FastAPI)
- Python version: 3.11 (latest stable)
- Additional features: API documentation, testing, type checking
Starting project setup...
[Phase 1] Initializing project structure...
✓ Created project with uv init
✓ Created directory structure
[Phase 2] Installing dependencies...
✓ Installed pytest, ruff, mypy
✓ Installed FastAPI and uvicorn
✓ Installed pydantic
[Phase 3] Creating configuration files...
✓ Created pyproject.toml with tool configurations
✓ Created .gitignore
✓ Created .vscode/settings.json
✓ Created README.md
[Phase 4] Setting up FastAPI application...
✓ Created API module structure
✓ Created sample endpoint
✓ Created API tests
[Phase 5] Running verification checks...
✓ Linting passed
✓ Type checking passed
✓ All tests passed (1 passed)
Setup complete! Your project is ready for development.
Next steps:
1. Activate your environment: cd weather-api
2. Run the API: uv run uvicorn weather_api.api.main:app --reload
3. Visit http://localhost:8000/docs for API documentation
Useful commands:
- uv run pytest # Run tests
- uv run ruff check . # Lint code
- uv add <package> # Add dependencies
```

34
commands/py-deps.md Normal file
View File

@@ -0,0 +1,34 @@
---
description: Manage Python dependencies with uv package manager
---
# Manage Python Dependencies
Add, update, or remove project dependencies using the uv package manager.
## Tasks to Complete
1. **Add Dependencies**
- For runtime: `uv add <package-name>`
- For development: `uv add --dev <package-name>`
- Confirm package was added to `pyproject.toml`
2. **Update Dependencies**
- Run `uv sync` to sync all dependencies
- Update specific package: `uv add <package-name>@latest`
- Report outdated packages if requested
3. **Remove Dependencies**
- Run `uv remove <package-name>` to remove a package
- Clean up unused dependencies
4. **Verify Environment**
- Ensure virtual environment is active
- Verify all dependencies are installed correctly
- Check for dependency conflicts
## Expected Outcome
- Up-to-date dependencies in sync with `pyproject.toml`
- Clean, conflict-free dependency tree
- Clear confirmation of changes made

51
commands/py-init.md Normal file
View File

@@ -0,0 +1,51 @@
---
description: Initialize a new Python project with modern tooling (uv, ruff, pytest)
---
# Initialize Python Project
Initialize a new Python project following modern best practices. This command sets up the project structure, tooling, and configuration.
## Tasks to Complete
1. **Project Initialization**
- Run `uv init <project-name>` to create the project
- Create `.python-version` file for pyenv compatibility
- Initialize git repository if not already present
2. **Directory Structure**
- Create `src/<project_name>/` for main code
- Create `tests/` directory for test files
- Create `.vscode/` for editor configuration
- Create `docs/` for documentation
3. **Essential Dependencies**
- Add `pytest` as dev dependency: `uv add --dev pytest`
- Add `ruff` as dev dependency: `uv add --dev ruff`
- Add `mypy` as dev dependency: `uv add --dev mypy`
- Add `pydantic` as runtime dependency: `uv add pydantic`
4. **Configuration Files**
- Create `pyproject.toml` with ruff and pytest configuration
- Create `.gitignore` for Python projects
- Create `.vscode/settings.json` with Python and ruff settings
5. **Documentation**
- Create `README.md` with project overview and setup instructions
- Create initial documentation structure
## Expected Outcome
A fully initialized Python project ready for development with:
- Modern package management (uv)
- Fast linting and formatting (ruff)
- Testing framework (pytest)
- Type checking (mypy)
- Editor configuration (VSCode)
- Version control (git)
## User Inputs Required
- Project name
- Python version (default: latest stable)
- Whether to include FastAPI for API projects

33
commands/py-lint.md Normal file
View File

@@ -0,0 +1,33 @@
---
description: Run ruff linter and formatter to check code quality
---
# Lint Python Code
Check and fix code quality issues using ruff, the fast Python linter and formatter.
## Tasks to Complete
1. **Run Linter**
- Execute `ruff check .` to identify issues
- Report all linting errors and warnings
- Categorize issues by severity
2. **Auto-fix Issues** (if requested)
- Run `ruff check --fix .` to automatically fix issues
- Report which issues were fixed automatically
3. **Format Code**
- Execute `ruff format .` to format all Python files
- Ensure PEP 8 compliance
- Report which files were reformatted
4. **Type Checking** (if mypy is installed)
- Run `mypy .` to check type annotations
- Report type errors with file locations
## Expected Outcome
- Clean, well-formatted code following PEP 8
- All auto-fixable issues resolved
- Clear report of remaining issues requiring manual intervention

30
commands/py-test.md Normal file
View File

@@ -0,0 +1,30 @@
---
description: Run pytest with proper configuration and coverage reporting
---
# Run Python Tests
Execute the project's test suite using pytest with appropriate options and coverage reporting.
## Tasks to Complete
1. **Run Tests**
- Execute `uv run pytest` to run all tests
- Display test results clearly
- Report any failures with details
2. **Coverage Analysis** (if requested)
- Run `uv run pytest --cov` for coverage report
- Generate HTML coverage report if needed
- Highlight areas needing more test coverage
3. **Test Filtering** (if requested)
- Run specific test files: `uv run pytest tests/test_specific.py`
- Run tests matching pattern: `uv run pytest -k "pattern"`
- Run only failed tests: `uv run pytest --lf`
## Expected Outcome
- Clear test results showing passes/failures
- Coverage percentages for each module
- Actionable information about test failures

24
hooks/hooks.json Normal file
View File

@@ -0,0 +1,24 @@
{
"hooks": {
"before-write": {
"enabled": false,
"command": "uv run ruff format {file_path}",
"description": "Auto-format Python files with ruff before writing"
},
"after-write": {
"enabled": false,
"command": "uv run ruff check --fix {file_path}",
"description": "Auto-fix linting issues after writing Python files"
},
"before-commit": {
"enabled": false,
"command": "uv run ruff check . && uv run mypy src && uv run pytest",
"description": "Run quality checks before git commits"
},
"test-on-save": {
"enabled": false,
"command": "uv run pytest tests/test_{file_name}",
"description": "Run related tests when saving Python files"
}
}
}

109
plugin.lock.json Normal file
View File

@@ -0,0 +1,109 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:jwplatta/prompt-library:claude/plugins/pythonic",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "3bd271a3eaa774f3948c904757be2be0468a0bd6",
"treeHash": "b8a9acc45ec9f46bfe197943456cf3b514b532d64b6a3794cff358bc78ac4726",
"generatedAt": "2025-11-28T10:19:23.602487Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "pythonic",
"description": "Python project setup and development workflows following modern best practices with uv, ruff, pytest, and FastAPI",
"version": "1.0.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "9838563a182b051ca1993450b2075c25b328cf7ad31ccaa8748256f7612d8c17"
},
{
"path": "agents/python-project-setup.md",
"sha256": "6e8bafbe19269314bcd2029646ef27f7291ebd169412505c3b446b6b68307fe5"
},
{
"path": "hooks/hooks.json",
"sha256": "ebbef10b9b0f36aba1f36fbe321baed17d2424d3f60690766759d40935c0d64c"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "7bdb436890f02f71f20df90af8591cd404a9756037966a7ffc664402efd40eba"
},
{
"path": "commands/py-test.md",
"sha256": "4bb5b1c4d0d9ac0114f2b402a2826f74cf27c32bedc6d456280fb4e58b3d2e80"
},
{
"path": "commands/py-deps.md",
"sha256": "7f151b7d9273a611f0ff978a1a4a4191b7fe64123117360f8d62331ef6a6f8bb"
},
{
"path": "commands/py-lint.md",
"sha256": "24cd57b6d2768dbf1d9ddb191c5a3ef4aae11dded71cbff685ff999ff93530cd"
},
{
"path": "commands/py-init.md",
"sha256": "dc779e1d29b9ac2f1a9fe015fe3265eb9e86d0766995973e0877cf056eab47d1"
},
{
"path": "skills/python-testing/SKILL.md",
"sha256": "45df6483b59934e9045b5e90a35662e058814c7efc0a7c42ad6fb0becf71c5f4"
},
{
"path": "skills/python-testing/pytest-configuration.md",
"sha256": "4d4eec92b86b7cec6d8335ffeb547d978b68eedb3b8a7b7e0374cfa46c7d0a78"
},
{
"path": "skills/python-code-quality/mypy-configuration.md",
"sha256": "1ac9a960b103a8477ae60a23e89142946fc94ab700e32dd70d5da508cb72a156"
},
{
"path": "skills/python-code-quality/ruff-configuration.md",
"sha256": "bb085d4dcdc8dfc30f3c7ef63774e2498c039559b5ffd792b56111aabaa846e8"
},
{
"path": "skills/python-code-quality/SKILL.md",
"sha256": "6d57263d199e152e02e0897c56bf55f6385645ab82c3c6b1334f2b1161b33f8b"
},
{
"path": "skills/python-project-setup/gitignore-template.md",
"sha256": "4d6dd9e788166e07134e8b68a7cd0ae5a7c8c0de413680e62397ba4d18ad2bcc"
},
{
"path": "skills/python-project-setup/pyproject-toml-template.md",
"sha256": "8a7cf6dc8ed3441e99ba4af55870a6ef130a47b065fcd6c86e034192d4bbcfa1"
},
{
"path": "skills/python-project-setup/project-structure-template.md",
"sha256": "3f962a1eee0416117bcd6dddcab5aaa1c4e90206768dab44b2661b242302113a"
},
{
"path": "skills/python-project-setup/readme-template.md",
"sha256": "b2802a5bf24d8b50faba8a74c204bc427ab6473b4bc1acd152a88eec99aa511e"
},
{
"path": "skills/python-project-setup/SKILL.md",
"sha256": "d1683bd2ba75f9e66a19e46cf2a207989623d5b4a8a8dea19b911917b8d1755c"
},
{
"path": "skills/python-project-setup/vscode-settings-template.json",
"sha256": "9d01afcc9033d9a8765a3ba72de599bac729de396a8a1b0247bd788932de6454"
}
],
"dirSha256": "b8a9acc45ec9f46bfe197943456cf3b514b532d64b6a3794cff358bc78ac4726"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View File

@@ -0,0 +1,89 @@
# Python Code Quality Skill
Ensure Python code follows best practices with automated linting, formatting, and type checking using ruff and mypy.
## When to Use This Skill
Use this skill when:
- User requests code linting or formatting
- User mentions code quality, PEP 8, or style issues
- User wants to fix linting errors
- User asks about type checking
- Code review processes require quality checks
## Core Capabilities
1. **Linting with Ruff**
- Check code for style violations
- Identify potential bugs and code smells
- Enforce PEP 8 compliance
- Auto-fix issues where possible
2. **Code Formatting**
- Format code consistently with ruff
- Organize imports automatically
- Ensure consistent indentation and line length
3. **Type Checking with Mypy**
- Verify type annotations are correct
- Catch type-related bugs before runtime
- Ensure type safety across the codebase
4. **Code Quality Metrics**
- Complexity analysis
- Dead code detection
- Unused import identification
## Context Files
This skill references the following context files in this directory:
- `ruff-configuration.md` - Ruff linting and formatting rules
- `mypy-configuration.md` - Type checking configuration
- `common-issues.md` - Common Python code quality issues and fixes
- `best-practices.md` - Python coding best practices
## Key Tools and Commands
```bash
# Linting
ruff check . # Check for issues
ruff check --fix . # Auto-fix issues
ruff check --watch . # Watch mode
# Formatting
ruff format . # Format all files
ruff format --check . # Check if formatting needed
# Type checking
mypy src # Check types
mypy --strict src # Strict mode
```
## Common Workflows
### Pre-commit Quality Check
```bash
ruff check --fix . && ruff format . && mypy src
```
### CI/CD Pipeline
```bash
ruff check . # Fail if unfixed issues
ruff format --check . # Fail if unformatted
mypy src # Fail on type errors
```
## Expected Outcomes
After using this skill:
- All code follows PEP 8 style guidelines
- Imports are properly organized
- Type hints are correct and comprehensive
- Code is consistently formatted
- Common bugs and issues are identified
## Integration with Other Skills
- Works with `python-project-setup` for initial configuration
- Complements `python-testing` for comprehensive quality assurance
- Used by `python-project-setup` agent for automated checks

View File

@@ -0,0 +1,374 @@
# Mypy Type Checking Configuration
Mypy is a static type checker for Python that helps catch bugs before runtime.
## Basic Configuration
Add to `pyproject.toml`:
```toml
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
strict_equality = true
show_error_codes = true
show_column_numbers = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
[[tool.mypy.overrides]]
module = "third_party_package.*"
ignore_missing_imports = true
```
## Strictness Levels
### Minimal (Getting Started)
```toml
[tool.mypy]
python_version = "3.11"
warn_return_any = false
warn_unused_configs = true
```
### Moderate (Recommended)
```toml
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
check_untyped_defs = true
```
### Strict (Maximum Safety)
```toml
[tool.mypy]
strict = true
python_version = "3.11"
```
## Common Configuration Options
### Type Checking Strictness
```toml
# Require type annotations
disallow_untyped_defs = true # Functions must have type hints
disallow_untyped_calls = true # Can't call untyped functions
disallow_incomplete_defs = true # All params must be typed
# Optional handling
no_implicit_optional = true # Optional must be explicit
strict_optional = true # None checking enabled
# Any type usage
disallow_any_unimported = false # Allow Any from untyped imports
disallow_any_expr = false # Forbid Any in expressions
disallow_any_decorated = false # Forbid Any in decorators
disallow_any_explicit = false # Forbid explicit Any
```
### Warning Messages
```toml
warn_return_any = true # Warn on returning Any
warn_redundant_casts = true # Warn on unnecessary casts
warn_unused_ignores = true # Warn on unused type: ignore
warn_unused_configs = true # Warn on unused config options
warn_no_return = true # Warn on missing returns
warn_unreachable = true # Warn on unreachable code
```
### Error Reporting
```toml
show_error_codes = true # Show error codes in messages
show_column_numbers = true # Show column numbers
pretty = true # Pretty print errors
color_output = true # Colorize output
error_summary = true # Show error summary
```
## Type Hints Guide
### Basic Types
```python
from typing import Any, Optional, Union
# Simple types
def greet(name: str) -> str:
return f"Hello, {name}"
# Optional (can be None)
def find_user(user_id: int) -> Optional[User]:
return user_map.get(user_id)
# Modern Optional syntax (Python 3.10+)
def find_user(user_id: int) -> User | None:
return user_map.get(user_id)
# Union types
def process(value: Union[int, str]) -> bool:
return True
# Modern Union syntax (Python 3.10+)
def process(value: int | str) -> bool:
return True
```
### Collections
```python
from typing import List, Dict, Set, Tuple
# Lists
def process_items(items: List[str]) -> List[int]:
return [len(item) for item in items]
# Modern syntax (Python 3.9+)
def process_items(items: list[str]) -> list[int]:
return [len(item) for item in items]
# Dictionaries
def get_config() -> Dict[str, Any]:
return {"key": "value"}
# Modern syntax
def get_config() -> dict[str, Any]:
return {"key": "value"}
# Sets
def unique_items(items: Set[int]) -> int:
return len(items)
# Tuples (fixed size)
def get_coordinates() -> Tuple[float, float]:
return (1.0, 2.0)
# Tuples (variable size)
def get_numbers() -> Tuple[int, ...]:
return (1, 2, 3, 4, 5)
```
### Callable Types
```python
from typing import Callable
# Function that takes int and returns str
Handler = Callable[[int], str]
def process(handler: Handler) -> None:
result = handler(42)
# Multiple parameters
Callback = Callable[[str, int], bool]
# No parameters
Factory = Callable[[], MyClass]
```
### Generic Types
```python
from typing import TypeVar, Generic
T = TypeVar('T')
class Container(Generic[T]):
def __init__(self, value: T) -> None:
self.value = value
def get(self) -> T:
return self.value
# Usage
container: Container[int] = Container(42)
value: int = container.get()
```
### Protocol Types
```python
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
def render(item: Drawable) -> None:
item.draw()
# Any class with draw() method works
class Circle:
def draw(self) -> None:
print("Drawing circle")
render(Circle()) # Type checks!
```
## Commands Reference
```bash
# Check all files
mypy src
# Check specific file
mypy src/module.py
# Strict mode
mypy --strict src
# Show error codes
mypy --show-error-codes src
# Generate type stubs
stubgen -p mypackage -o stubs
# Check against installed packages
mypy --install-types
mypy --non-interactive --install-types
```
## Common Errors and Fixes
### Error: "Argument has incompatible type"
```python
# Problem
def greet(name: str) -> str:
return f"Hello, {name}"
greet(123) # Error: Argument 1 has incompatible type "int"
# Fix: Pass correct type
greet("World")
# Or: Convert type
greet(str(123))
```
### Error: "Function is missing a return statement"
```python
# Problem
def get_value() -> int:
if condition:
return 42
# Missing return!
# Fix: Add return for all paths
def get_value() -> int:
if condition:
return 42
return 0
```
### Error: "Need type annotation"
```python
# Problem
items = [] # Error: Need type annotation
# Fix: Add type annotation
items: list[str] = []
# Or: Initialize with values
items = ["a", "b", "c"]
```
### Error: "Incompatible return type"
```python
# Problem
def get_name() -> str:
return None # Error: Incompatible return
# Fix: Use Optional
def get_name() -> str | None:
return None
```
## Ignoring Errors
```python
# Ignore single line
result = unsafe_function() # type: ignore
# Ignore with reason
result = unsafe_function() # type: ignore[arg-type]
# Ignore entire file
# mypy: ignore-errors
```
## Third-Party Package Stubs
### Installing Type Stubs
```bash
# Install stubs for requests
uv add --dev types-requests
# Common stubs
uv add --dev types-requests
uv add --dev types-redis
uv add --dev types-PyYAML
```
### Handling Missing Stubs
```toml
[[tool.mypy.overrides]]
module = "untyped_package.*"
ignore_missing_imports = true
```
## VSCode Integration
Add to `.vscode/settings.json`:
```json
{
"python.linting.mypyEnabled": true,
"python.linting.enabled": true,
"python.analysis.typeCheckingMode": "basic"
}
```
## Best Practices
1. **Start gradual**: Enable mypy gradually, module by module
2. **Use strict mode**: `strict = true` for new projects
3. **Add type hints everywhere**: Functions, methods, variables
4. **Use Protocol for duck typing**: Better than inheritance
5. **Leverage modern syntax**: Use `list` instead of `List` (Python 3.9+)
6. **Install type stubs**: For all third-party packages
7. **Run in CI**: Fail builds on type errors
8. **Document with types**: Types serve as documentation
## Incremental Adoption
```toml
# Start with specific directories
[tool.mypy]
files = ["src/critical_module"]
strict = true
# Gradually expand
files = ["src/critical_module", "src/api"]
# Eventually cover everything
files = ["src"]
```

View File

@@ -0,0 +1,229 @@
# Ruff Configuration Guide
Ruff is a fast Python linter and formatter that replaces multiple tools (isort, flake8, pyupgrade, etc.).
## Basic Configuration
Add to `pyproject.toml`:
```toml
[tool.ruff]
line-length = 100
target-version = "py311"
src = ["src", "tests"]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
"ARG", # flake8-unused-arguments
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
"RUF", # Ruff-specific rules
]
ignore = [
"E501", # line too long (handled by formatter)
"B008", # do not perform function calls in argument defaults
]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = [
"ARG", # Unused function arguments allowed in tests
"S101", # Assert allowed in tests
]
"__init__.py" = [
"F401", # Unused imports allowed in __init__.py
]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"
[tool.ruff.lint.isort]
known-first-party = ["project_name"]
```
## Rule Categories
### Error Detection (E, W, F)
- **E**: PEP 8 style errors
- **W**: PEP 8 style warnings
- **F**: PyFlakes logical errors
### Code Quality (B, C4, SIM)
- **B**: Bugbear - likely bugs and design problems
- **C4**: Comprehensions - simplify list/dict/set comprehensions
- **SIM**: Simplify - code simplification suggestions
### Modernization (UP)
- **UP**: PyUpgrade - use modern Python syntax
- `typing.List``list`
- `Optional[str]``str | None` (Python 3.10+)
### Organization (I)
- **I**: isort - import sorting and organization
### Performance (ARG, TCH)
- **ARG**: Detect unused function arguments
- **TCH**: Type checking imports (move to TYPE_CHECKING block)
## Common Rules
### E/W Series (PEP 8)
- `E111`: Indentation is not a multiple of 4
- `E201`: Whitespace after '('
- `E202`: Whitespace before ')'
- `E203`: Whitespace before ':'
- `E302`: Expected 2 blank lines
- `E303`: Too many blank lines
- `W291`: Trailing whitespace
### F Series (PyFlakes)
- `F401`: Unused import
- `F811`: Redefinition of unused name
- `F821`: Undefined name
- `F841`: Local variable assigned but never used
### B Series (Bugbear)
- `B002`: Using * in exception handling
- `B006`: Mutable default argument
- `B007`: Loop variable not used
- `B008`: Function calls in default arguments
- `B904`: Use `raise ... from ...` for exception chaining
### UP Series (PyUpgrade)
- `UP006`: Use `list` instead of `typing.List`
- `UP007`: Use `X | Y` instead of `typing.Union[X, Y]`
- `UP032`: Use f-strings instead of `.format()`
## Commands Reference
### Linting
```bash
# Check all files
ruff check .
# Check specific file
ruff check src/module.py
# Auto-fix issues
ruff check --fix .
# Show fixes without applying
ruff check --diff .
# Watch mode (re-run on file changes)
ruff check --watch .
# Output JSON format
ruff check --output-format=json .
```
### Formatting
```bash
# Format all files
ruff format .
# Format specific file
ruff format src/module.py
# Check if formatting needed (CI)
ruff format --check .
# Show diff without applying
ruff format --diff .
```
### Configuration Testing
```bash
# Show active configuration
ruff check --show-settings
# Show all available rules
ruff rule --all
# Show specific rule documentation
ruff rule F401
```
## Per-File Ignores
Ignore specific rules for specific files:
```toml
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["ARG", "S101"] # Tests can use assert and unused args
"__init__.py" = ["F401"] # Unused imports OK in __init__
"scripts/**/*.py" = ["T201"] # print() OK in scripts
"migrations/**/*.py" = ["E501"] # Long lines OK in migrations
```
## VSCode Integration
Add to `.vscode/settings.json`:
```json
{
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll": "explicit"
}
},
"ruff.enable": true,
"ruff.lint.enable": true,
"ruff.format.enable": true
}
```
## Performance Tips
Ruff is extremely fast (10-100x faster than alternatives):
- Written in Rust for performance
- Parallel processing by default
- Incremental linting in watch mode
- Caching for repeated runs
## Migration from Other Tools
### From Black
Ruff's formatter is compatible with Black:
```bash
ruff format . # Replaces: black .
```
### From isort
```bash
ruff check --select I --fix . # Replaces: isort .
```
### From flake8
```bash
ruff check . # Replaces: flake8 .
```
### From pyupgrade
```bash
ruff check --select UP --fix . # Replaces: pyupgrade .
```
## Best Practices
1. **Run formatter last**: `ruff check --fix . && ruff format .`
2. **Use in CI**: Check both linting and formatting
3. **Configure per-file ignores**: For tests, init files, migrations
4. **Enable auto-fix**: Most issues can be fixed automatically
5. **Use with pre-commit**: Run checks before commits
6. **Review rule changes**: Stay updated with new releases

View File

@@ -0,0 +1,76 @@
# Python Project Setup Skill
Set up new Python projects following modern best practices with uv, ruff, pytest, and proper project structure.
## When to Use This Skill
Use this skill when:
- User requests to create a new Python project
- User wants to initialize Python tooling in an existing directory
- User mentions setting up a Python development environment
- User asks about Python project structure or best practices
## Core Capabilities
1. **Project Initialization**
- Initialize projects with `uv init`
- Set up proper directory structure
- Configure Python version with pyenv
2. **Dependency Management**
- Install and configure uv package manager
- Add essential dependencies (pytest, ruff, mypy, pydantic)
- Set up development vs runtime dependencies
3. **Configuration Files**
- Create `pyproject.toml` with tool configurations
- Set up `.gitignore` for Python projects
- Configure VSCode settings for Python development
- Create `.python-version` for version management
4. **Project Structure**
- Create `src/<project_name>/` for source code
- Set up `tests/` directory for test files
- Create `docs/` for documentation
- Set up `.vscode/` for editor configuration
## Context Files
This skill references the following context files in this directory:
- `project-structure-template.md` - Standard directory layout
- `pyproject-toml-template.md` - Configuration template
- `vscode-settings-template.json` - Editor configuration
- `gitignore-template.md` - Python gitignore patterns
- `readme-template.md` - README structure
## Key Tools and Commands
```bash
# Project initialization
uv init <project-name>
# Dependency management
uv add pytest --dev
uv add ruff --dev
uv add mypy --dev
uv add pydantic
# Sync dependencies
uv sync
```
## Expected Outcomes
After using this skill, the user should have:
- A fully initialized Python project with modern tooling
- Proper project structure following best practices
- All essential dependencies installed
- Configuration files set up correctly
- Version control initialized (git)
- Documentation scaffolding in place
## Integration with Other Skills
- Works with `python-code-quality` skill for linting setup
- Works with `python-testing` skill for test framework configuration
- Complements the `python-project-setup` agent for full orchestration

View File

@@ -0,0 +1,209 @@
# Python .gitignore Template
```gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
Pipfile.lock
# poetry
poetry.lock
# pdm
.pdm.toml
# PEP 582
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# Ruff
.ruff_cache/
# uv
uv.lock
# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Project specific
*.db
*.sqlite
*.sqlite3
data/
logs/
tmp/
temp/
```
## Explanation of Key Patterns
### Python Runtime Files
- `__pycache__/` - Compiled bytecode cache
- `*.pyc`, `*.pyo`, `*.pyd` - Compiled Python files
- `*.so` - Compiled C extensions
### Package/Build Artifacts
- `dist/`, `build/` - Build output directories
- `*.egg-info/` - Package metadata
- `.eggs/` - Installed packages directory
### Virtual Environments
- `.venv/`, `venv/`, `env/` - Virtual environment directories
- Always create virtual environments, never commit them
### Testing & Coverage
- `.pytest_cache/` - Pytest cache
- `.coverage` - Coverage data files
- `htmlcov/` - HTML coverage reports
### Type Checking & Linting
- `.mypy_cache/` - Mypy cache
- `.ruff_cache/` - Ruff cache
- `.pytype/` - Pytype cache
### Documentation
- `docs/_build/` - Sphinx build output
- `/site` - MkDocs build output
### Environment Variables
- `.env` - Environment variable files (NEVER commit these)
- Should contain secrets, API keys, database URLs
### IDE Files
- `.vscode/` - VSCode settings (some teams commit this)
- `.idea/` - PyCharm settings
- `.DS_Store` - macOS file system metadata
## Customization Tips
1. **Commit `.vscode/` if desired**: Remove from .gitignore to share editor settings
2. **Project-specific data**: Add custom directories for data files, logs, etc.
3. **Lock files**: Consider keeping `uv.lock` for reproducible builds
4. **Documentation**: Remove `docs/_build/` if you want to commit built docs

View File

@@ -0,0 +1,112 @@
# Python Project Structure Template
## Standard Directory Layout
```
project_name/
├── .vscode/ # VSCode editor configuration
│ ├── settings.json # Python, ruff, mypy settings
│ └── launch.json # Debug configurations
├── src/ # Source code directory
│ └── project_name/ # Main package (use underscores)
│ ├── __init__.py # Package initialization
│ ├── main.py # Entry point (if applicable)
│ ├── models/ # Data models (Pydantic)
│ ├── services/ # Business logic
│ ├── api/ # API routes (if using FastAPI)
│ └── utils/ # Utility functions
├── tests/ # Test directory
│ ├── __init__.py
│ ├── conftest.py # Pytest fixtures
│ ├── test_main.py # Test files (prefix with test_)
│ └── integration/ # Integration tests
├── docs/ # Documentation
│ ├── index.md
│ └── api/ # API documentation
├── .github/ # GitHub configuration
│ ├── workflows/ # CI/CD workflows
│ │ └── test.yml
│ └── dependabot.yml # Dependency updates
├── .gitignore # Git ignore patterns
├── .python-version # Python version for pyenv
├── pyproject.toml # Project metadata and dependencies
├── README.md # Project documentation
└── uv.lock # Locked dependencies (generated)
```
## File Naming Conventions
- **Python packages**: Use underscores (e.g., `my_package`)
- **Project names**: Use underscores (e.g., `my_project`)
- **Test files**: Prefix with `test_` (e.g., `test_models.py`)
- **Private modules**: Prefix with `_` (e.g., `_internal.py`)
## Directory Purpose
### `src/project_name/`
Main application code organized by function:
- `models/` - Data classes, Pydantic models, database models
- `services/` - Business logic and service layer
- `api/` - API endpoints and route handlers (FastAPI)
- `utils/` - Helper functions and utilities
- `config/` - Configuration management
### `tests/`
Test files mirroring the structure of `src/`:
- Unit tests for each module
- Integration tests in `integration/` subdirectory
- `conftest.py` for shared fixtures
- Use pytest conventions
### `docs/`
Project documentation:
- User guides
- API documentation
- Architecture decisions
- Setup instructions
## Module Organization
Each Python module should follow this pattern:
```python
# frozen_string_literal equivalent in Python
"""Module docstring describing purpose."""
from typing import Any, Optional
import third_party_package
from project_name import local_module
class MyClass:
"""Class docstring."""
def __init__(self, param: str) -> None:
"""Initialize with param."""
self.param = param
def method(self) -> str:
"""Method docstring."""
return self.param
def public_function() -> None:
"""Public function docstring."""
pass
def _private_function() -> None:
"""Private helper function."""
pass
```
## Best Practices
1. **Use `src/` layout**: Prevents accidental imports of local code
2. **Type hints everywhere**: Add type annotations to all functions
3. **Docstrings**: Document all public classes and functions
4. **Test organization**: Mirror source structure in tests
5. **Configuration**: Use environment variables or config files, never hardcode
6. **Dependencies**: Separate dev dependencies from runtime dependencies

View File

@@ -0,0 +1,226 @@
# pyproject.toml Template
## Complete Configuration Template
```toml
[project]
name = "project-name"
version = "0.1.0"
description = "Project description"
readme = "README.md"
requires-python = ">=3.11"
license = {text = "MIT"}
authors = [
{name = "Your Name", email = "you@example.com"}
]
keywords = ["python", "example"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = [
"pydantic>=2.0.0",
# Add runtime dependencies here
]
[project.optional-dependencies]
dev = [
"pytest>=8.0.0",
"pytest-cov>=4.1.0",
"ruff>=0.3.0",
"mypy>=1.8.0",
]
api = [
"fastapi>=0.110.0",
"uvicorn[standard]>=0.27.0",
]
docs = [
"mkdocs>=1.5.0",
"mkdocs-material>=9.5.0",
]
[project.urls]
Homepage = "https://github.com/username/project-name"
Repository = "https://github.com/username/project-name"
Documentation = "https://project-name.readthedocs.io"
Issues = "https://github.com/username/project-name/issues"
[project.scripts]
# Define CLI entry points
project-cli = "project_name.cli:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/project_name"]
# Ruff configuration
[tool.ruff]
line-length = 100
target-version = "py311"
src = ["src", "tests"]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
"ARG", # flake8-unused-arguments
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
]
ignore = [
"E501", # line too long (handled by formatter)
"B008", # do not perform function calls in argument defaults
"B904", # raise from None
]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = [
"ARG", # Unused function arguments allowed in tests
"S101", # Assert allowed in tests
]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"
# Pytest configuration
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--showlocals",
"-ra",
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"integration: marks tests as integration tests",
]
# Coverage configuration
[tool.coverage.run]
source = ["src"]
branch = true
omit = [
"*/tests/*",
"*/__init__.py",
]
[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"@abstractmethod",
]
# Mypy configuration
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
strict_equality = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
# UV-specific configuration (if needed)
[tool.uv]
dev-dependencies = [
"pytest>=8.0.0",
"pytest-cov>=4.1.0",
"ruff>=0.3.0",
"mypy>=1.8.0",
]
```
## Configuration Sections Explained
### `[project]`
Basic project metadata used by build tools and package indexes.
### `[project.optional-dependencies]`
Groups of optional dependencies for different use cases:
- `dev` - Development tools (testing, linting)
- `api` - API framework dependencies (FastAPI, uvicorn)
- `docs` - Documentation generation tools
### `[tool.ruff]`
Ruff linter and formatter configuration:
- Fast Python linter combining multiple tools
- Replaces isort, flake8, pyupgrade, and more
- Automatic code formatting
### `[tool.pytest.ini_options]`
Pytest test framework configuration:
- Test discovery patterns
- Default command-line options
- Custom test markers
### `[tool.coverage]`
Code coverage settings for pytest-cov:
- Which files to measure
- Coverage reporting options
- Lines to exclude from coverage
### `[tool.mypy]`
Type checking configuration:
- Strictness settings
- Type checking rules
- Per-directory overrides
## Usage Examples
```bash
# Install project with dev dependencies
uv sync --extra dev
# Install with API dependencies
uv sync --extra api
# Install all optional dependencies
uv sync --all-extras
# Run tests with coverage
uv run pytest --cov
# Lint code
uv run ruff check .
# Format code
uv run ruff format .
# Type check
uv run mypy src
```

View File

@@ -0,0 +1,332 @@
# README.md Template
```markdown
# Project Name
Brief one-line description of what this project does.
## Overview
A more detailed description of the project, its purpose, and key features.
## Features
- Feature 1: Description
- Feature 2: Description
- Feature 3: Description
## Requirements
- Python 3.11 or higher
- uv package manager
## Installation
### Using uv (Recommended)
\`\`\`bash
# Clone the repository
git clone https://github.com/username/project-name.git
cd project-name
# Install dependencies
uv sync
# Activate virtual environment (optional, uv runs commands automatically)
source .venv/bin/activate # On Unix/macOS
.venv\Scripts\activate # On Windows
\`\`\`
### Using pip
\`\`\`bash
pip install -e .
\`\`\`
## Quick Start
\`\`\`python
from project_name import main_function
# Example usage
result = main_function()
print(result)
\`\`\`
## Usage
### Command Line Interface
\`\`\`bash
# Run the main application
uv run python -m project_name
# Or if you installed with pip
project-cli --help
\`\`\`
### As a Library
\`\`\`python
from project_name import SomeClass
# Create an instance
instance = SomeClass(param="value")
# Use the instance
result = instance.method()
\`\`\`
## Development
### Setup Development Environment
\`\`\`bash
# Install with development dependencies
uv sync --extra dev
# Or install all extras
uv sync --all-extras
\`\`\`
### Running Tests
\`\`\`bash
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov
# Run specific test file
uv run pytest tests/test_specific.py
# Run with verbose output
uv run pytest -v
\`\`\`
### Code Quality
\`\`\`bash
# Lint code
uv run ruff check .
# Fix auto-fixable issues
uv run ruff check --fix .
# Format code
uv run ruff format .
# Type checking
uv run mypy src
\`\`\`
### Pre-commit Checks
Before committing, ensure all checks pass:
\`\`\`bash
# Run all checks
uv run ruff check . && uv run ruff format . && uv run mypy src && uv run pytest
\`\`\`
## Project Structure
\`\`\`
project-name/
├── src/
│ └── project_name/ # Main package
│ ├── __init__.py
│ ├── main.py # Entry point
│ ├── models/ # Data models
│ ├── services/ # Business logic
│ └── utils/ # Utilities
├── tests/ # Test files
├── docs/ # Documentation
├── pyproject.toml # Project configuration
└── README.md # This file
\`\`\`
## Configuration
### Environment Variables
Create a `.env` file in the project root:
\`\`\`env
API_KEY=your_api_key_here
DATABASE_URL=postgresql://user:pass@localhost/dbname
DEBUG=false
\`\`\`
### Configuration File
Alternatively, create a `config.yaml`:
\`\`\`yaml
api:
key: your_api_key
timeout: 30
database:
url: postgresql://user:pass@localhost/dbname
pool_size: 5
\`\`\`
## API Documentation
### Main Classes
#### `SomeClass`
Description of the class.
\`\`\`python
from project_name import SomeClass
instance = SomeClass(param="value")
result = instance.method()
\`\`\`
**Parameters:**
- `param` (str): Description of parameter
**Returns:**
- `str`: Description of return value
### Functions
#### `main_function()`
Description of the function.
\`\`\`python
from project_name import main_function
result = main_function()
\`\`\`
## API Endpoints (if applicable)
### Start the Server
\`\`\`bash
uv run uvicorn project_name.api.main:app --reload
\`\`\`
### Endpoints
#### GET `/api/items`
Get all items.
**Response:**
\`\`\`json
{
"items": [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
]
}
\`\`\`
#### POST `/api/items`
Create a new item.
**Request Body:**
\`\`\`json
{
"name": "New Item"
}
\`\`\`
**Response:**
\`\`\`json
{
"id": 3,
"name": "New Item"
}
\`\`\`
## Contributing
Contributions are welcome! Please follow these steps:
1. Fork the repository
2. Create a feature branch (\`git checkout -b feature/amazing-feature\`)
3. Make your changes
4. Run tests and linting (\`uv run pytest && uv run ruff check .\`)
5. Commit your changes (\`git commit -m 'Add amazing feature'\`)
6. Push to the branch (\`git push origin feature/amazing-feature\`)
7. Open a Pull Request
### Code Style
- Follow PEP 8 guidelines
- Use type hints for all functions
- Write docstrings for all public APIs
- Maintain test coverage above 80%
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Authors
- Your Name - [@yourhandle](https://github.com/yourhandle)
## Acknowledgments
- Library or resource that inspired this project
- Contributors who helped
- Any other acknowledgments
## Changelog
### [0.1.0] - 2024-01-01
#### Added
- Initial release
- Basic functionality
#### Changed
- Nothing yet
#### Fixed
- Nothing yet
## Support
For support, email support@example.com or open an issue on GitHub.
## Links
- [Documentation](https://project-name.readthedocs.io)
- [Issue Tracker](https://github.com/username/project-name/issues)
- [Changelog](CHANGELOG.md)
```
## Sections Explained
1. **Title & Description**: Clear project name and one-line summary
2. **Overview**: More detailed description of purpose and features
3. **Installation**: Step-by-step setup instructions
4. **Quick Start**: Minimal example to get started quickly
5. **Usage**: Detailed usage examples (CLI and library)
6. **Development**: Instructions for contributors
7. **Project Structure**: Overview of codebase organization
8. **Configuration**: How to configure the application
9. **API Documentation**: Documentation of public API
10. **Contributing**: Guidelines for contributions
11. **License & Authors**: Legal and attribution information
12. **Support**: How to get help
## Tips for Good READMEs
- **Keep it concise**: Users should understand the project in 30 seconds
- **Working examples**: All code examples should be copy-paste ready
- **Clear installation**: Step-by-step instructions that actually work
- **Visual aids**: Consider adding screenshots, diagrams, or GIFs
- **Badges**: Add CI status, coverage, and version badges
- **Update regularly**: Keep it in sync with the actual codebase

View File

@@ -0,0 +1,54 @@
{
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"python.analysis.typeCheckingMode": "basic",
"python.analysis.autoImportCompletions": true,
"python.analysis.diagnosticMode": "workspace",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll": "explicit"
},
"editor.rulers": [100]
},
"ruff.enable": true,
"ruff.lint.enable": true,
"ruff.format.enable": true,
"ruff.organizeImports": true,
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.pytestArgs": [
"tests"
],
"files.exclude": {
"**/__pycache__": true,
"**/*.pyc": true,
"**/*.pyo": true,
"**/.pytest_cache": true,
"**/.mypy_cache": true,
"**/.ruff_cache": true,
"**/*.egg-info": true
},
"files.watcherExclude": {
"**/__pycache__/**": true,
"**/.venv/**": true,
"**/.pytest_cache/**": true,
"**/.mypy_cache/**": true,
"**/.ruff_cache/**": true
},
"search.exclude": {
"**/.venv": true,
"**/node_modules": true,
"**/__pycache__": true,
"**/.pytest_cache": true,
"**/.mypy_cache": true,
"**/.ruff_cache": true
}
}

View File

@@ -0,0 +1,111 @@
# Python Testing Skill
Comprehensive testing with pytest including unit tests, integration tests, fixtures, and coverage reporting.
## When to Use This Skill
Use this skill when:
- User requests to run tests
- User wants to create new tests
- User asks about test coverage
- User mentions pytest, unit tests, or integration tests
- Debugging test failures
## Core Capabilities
1. **Test Execution**
- Run all tests or specific test files
- Run tests matching patterns
- Run only failed tests
- Generate test reports
2. **Test Coverage**
- Measure code coverage
- Generate HTML coverage reports
- Identify untested code
- Set coverage thresholds
3. **Test Writing**
- Create unit tests for functions and classes
- Write integration tests
- Use pytest fixtures effectively
- Implement parametrized tests
4. **Test Organization**
- Structure test files properly
- Use conftest.py for shared fixtures
- Organize tests by feature or module
- Mark tests for selective execution
## Context Files
This skill references the following context files in this directory:
- `pytest-configuration.md` - Pytest setup and configuration
- `test-patterns.md` - Common testing patterns and examples
- `fixtures-guide.md` - Using pytest fixtures
- `coverage-guide.md` - Code coverage best practices
## Key Tools and Commands
```bash
# Run tests
uv run pytest # All tests
uv run pytest tests/test_file.py # Specific file
uv run pytest -k "pattern" # Tests matching pattern
uv run pytest --lf # Last failed only
# Coverage
uv run pytest --cov # With coverage
uv run pytest --cov --cov-report=html # HTML report
uv run pytest --cov --cov-report=term-missing # Show missing lines
# Output control
uv run pytest -v # Verbose
uv run pytest -s # Show print statements
uv run pytest -x # Stop on first failure
```
## Common Test Patterns
### Unit Test Example
```python
def test_addition():
assert add(2, 3) == 5
assert add(-1, 1) == 0
```
### Fixture Usage
```python
@pytest.fixture
def sample_data():
return {"key": "value"}
def test_with_fixture(sample_data):
assert sample_data["key"] == "value"
```
### Parametrized Tests
```python
@pytest.mark.parametrize("input,expected", [
(2, 4),
(3, 9),
(4, 16),
])
def test_square(input, expected):
assert square(input) == expected
```
## Expected Outcomes
After using this skill:
- Comprehensive test suite covering critical functionality
- High test coverage (ideally > 80%)
- Well-organized test files
- Clear test failure messages
- Fast test execution
## Integration with Other Skills
- Works with `python-project-setup` for test directory structure
- Complements `python-code-quality` for comprehensive QA
- Used by `python-project-setup` agent for automated testing

View File

@@ -0,0 +1,447 @@
# Pytest Configuration Guide
Pytest is a powerful testing framework for Python that makes it easy to write simple and scalable tests.
## Installation
```bash
uv add --dev pytest
uv add --dev pytest-cov # For coverage
uv add --dev pytest-mock # For mocking
uv add --dev pytest-asyncio # For async tests
```
## Basic Configuration
Add to `pyproject.toml`:
```toml
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--showlocals",
"-ra",
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"integration: marks tests as integration tests",
"unit: marks tests as unit tests",
]
```
## Directory Structure
```
project/
├── src/
│ └── project_name/
│ └── module.py
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Shared fixtures
│ ├── test_module.py # Unit tests
│ ├── integration/
│ │ ├── __init__.py
│ │ └── test_api.py # Integration tests
│ └── fixtures/
│ └── sample_data.json
```
## Writing Tests
### Basic Test Function
```python
def test_simple_addition():
"""Test that addition works correctly."""
result = add(2, 3)
assert result == 5
```
### Test Class
```python
class TestCalculator:
"""Tests for Calculator class."""
def test_addition(self):
calc = Calculator()
assert calc.add(2, 3) == 5
def test_subtraction(self):
calc = Calculator()
assert calc.subtract(5, 3) == 2
```
### Using Assertions
```python
def test_assertions():
# Equality
assert result == expected
# Boolean
assert is_valid()
assert not is_invalid()
# Membership
assert item in collection
assert key in dictionary
# Type checking
assert isinstance(obj, MyClass)
# Exceptions
with pytest.raises(ValueError):
raise_error()
# Approximate equality (floats)
assert result == pytest.approx(expected, rel=1e-5)
```
## Fixtures
### Basic Fixture
```python
import pytest
@pytest.fixture
def sample_user():
"""Create a sample user for testing."""
return User(name="Alice", age=30)
def test_user_greeting(sample_user):
assert sample_user.greet() == "Hello, I'm Alice"
```
### Fixture Scopes
```python
@pytest.fixture(scope="function") # Default, new instance per test
def function_scope():
return setup()
@pytest.fixture(scope="class") # One instance per test class
def class_scope():
return setup()
@pytest.fixture(scope="module") # One instance per module
def module_scope():
return setup()
@pytest.fixture(scope="session") # One instance per test session
def session_scope():
return setup()
```
### Fixture Cleanup
```python
@pytest.fixture
def resource():
# Setup
res = acquire_resource()
yield res
# Teardown
res.cleanup()
# Or using context manager
@pytest.fixture
def database():
with create_database() as db:
yield db
# Automatic cleanup
```
### Fixture Dependencies
```python
@pytest.fixture
def database():
return Database()
@pytest.fixture
def user_repository(database):
return UserRepository(database)
def test_find_user(user_repository):
user = user_repository.find(1)
assert user is not None
```
## Parametrized Tests
### Basic Parametrization
```python
@pytest.mark.parametrize("input,expected", [
(2, 4),
(3, 9),
(4, 16),
(5, 25),
])
def test_square(input, expected):
assert square(input) == expected
```
### Multiple Parameters
```python
@pytest.mark.parametrize("a,b,expected", [
(1, 1, 2),
(2, 3, 5),
(10, -5, 5),
])
def test_addition(a, b, expected):
assert add(a, b) == expected
```
### Parametrizing Fixtures
```python
@pytest.fixture(params=[1, 2, 3])
def number(request):
return request.param
def test_with_different_numbers(number):
assert number > 0
```
## Test Markers
### Built-in Markers
```python
@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
pass
@pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10+")
def test_new_feature():
pass
@pytest.mark.xfail(reason="Known bug")
def test_buggy_feature():
pass
```
### Custom Markers
```python
# Define in pyproject.toml
# markers = ["slow: marks tests as slow"]
@pytest.mark.slow
def test_expensive_operation():
# Long-running test
pass
# Run with: pytest -m "not slow"
```
## Exception Testing
```python
def test_raises_value_error():
with pytest.raises(ValueError):
raise ValueError("Invalid value")
def test_raises_with_message():
with pytest.raises(ValueError, match="Invalid"):
raise ValueError("Invalid value")
def test_exception_info():
with pytest.raises(ValueError) as exc_info:
raise ValueError("Invalid value")
assert "Invalid" in str(exc_info.value)
```
## Mocking
### Using pytest-mock
```python
def test_with_mock(mocker):
# Mock a function
mock = mocker.patch('module.function')
mock.return_value = 42
result = call_function()
assert result == 42
mock.assert_called_once()
def test_mock_method(mocker):
# Mock a method
mock = mocker.patch.object(MyClass, 'method')
mock.return_value = "mocked"
obj = MyClass()
assert obj.method() == "mocked"
```
### Using unittest.mock
```python
from unittest.mock import Mock, patch
def test_with_mock():
with patch('module.function') as mock:
mock.return_value = 42
result = call_function()
assert result == 42
```
## Async Tests
```python
import pytest
@pytest.mark.asyncio
async def test_async_function():
result = await async_operation()
assert result == expected
@pytest.fixture
async def async_client():
client = AsyncClient()
yield client
await client.close()
@pytest.mark.asyncio
async def test_with_async_fixture(async_client):
result = await async_client.get("/endpoint")
assert result.status_code == 200
```
## Running Tests
```bash
# All tests
pytest
# Specific file
pytest tests/test_module.py
# Specific test
pytest tests/test_module.py::test_function
# Specific class
pytest tests/test_module.py::TestClass
# Pattern matching
pytest -k "test_user"
# Markers
pytest -m slow # Only slow tests
pytest -m "not slow" # Exclude slow tests
# Last failed
pytest --lf
# Failed first
pytest --ff
# Stop on first failure
pytest -x
# Stop after N failures
pytest --maxfail=3
# Verbose output
pytest -v
# Show print statements
pytest -s
# Show locals in tracebacks
pytest --showlocals
# Parallel execution (requires pytest-xdist)
pytest -n auto
```
## conftest.py
Shared configuration and fixtures:
```python
# tests/conftest.py
import pytest
@pytest.fixture(scope="session")
def database():
"""Create database for entire test session."""
db = create_test_database()
yield db
db.drop()
@pytest.fixture(autouse=True)
def reset_database(database):
"""Reset database before each test."""
database.clear()
def pytest_configure(config):
"""Pytest configuration hook."""
config.addinivalue_line(
"markers", "integration: mark test as integration test"
)
```
## Best Practices
1. **One assertion per test**: Keep tests focused
2. **Descriptive names**: Use `test_user_creation_with_valid_data`
3. **AAA pattern**: Arrange, Act, Assert
4. **Use fixtures**: Avoid duplicating setup code
5. **Test edge cases**: Not just happy paths
6. **Fast tests**: Keep unit tests under 100ms
7. **Independent tests**: Tests should not depend on each other
8. **Clear assertions**: Make failures obvious
## Example Test File
```python
"""Tests for user module."""
import pytest
from project_name.models import User
@pytest.fixture
def valid_user_data():
"""Valid user data for testing."""
return {
"name": "Alice",
"email": "alice@example.com",
"age": 30
}
class TestUser:
"""Tests for User model."""
def test_create_user(self, valid_user_data):
"""Test creating a user with valid data."""
# Arrange & Act
user = User(**valid_user_data)
# Assert
assert user.name == "Alice"
assert user.email == "alice@example.com"
assert user.age == 30
def test_user_greeting(self, valid_user_data):
"""Test user greeting message."""
user = User(**valid_user_data)
assert user.greet() == "Hello, I'm Alice"
@pytest.mark.parametrize("age", [-1, 0, 151])
def test_invalid_age(self, valid_user_data, age):
"""Test that invalid ages raise ValueError."""
valid_user_data["age"] = age
with pytest.raises(ValueError, match="Invalid age"):
User(**valid_user_data)
```