Initial commit
This commit is contained in:
20
.claude-plugin/plugin.json
Normal file
20
.claude-plugin/plugin.json
Normal 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
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# pythonic
|
||||
|
||||
Python project setup and development workflows following modern best practices with uv, ruff, pytest, and FastAPI
|
||||
376
agents/python-project-setup.md
Normal file
376
agents/python-project-setup.md
Normal 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
34
commands/py-deps.md
Normal 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
51
commands/py-init.md
Normal 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
33
commands/py-lint.md
Normal 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
30
commands/py-test.md
Normal 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
24
hooks/hooks.json
Normal 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
109
plugin.lock.json
Normal 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": []
|
||||
}
|
||||
}
|
||||
89
skills/python-code-quality/SKILL.md
Normal file
89
skills/python-code-quality/SKILL.md
Normal 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
|
||||
374
skills/python-code-quality/mypy-configuration.md
Normal file
374
skills/python-code-quality/mypy-configuration.md
Normal 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"]
|
||||
```
|
||||
229
skills/python-code-quality/ruff-configuration.md
Normal file
229
skills/python-code-quality/ruff-configuration.md
Normal 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
|
||||
76
skills/python-project-setup/SKILL.md
Normal file
76
skills/python-project-setup/SKILL.md
Normal 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
|
||||
209
skills/python-project-setup/gitignore-template.md
Normal file
209
skills/python-project-setup/gitignore-template.md
Normal 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
|
||||
112
skills/python-project-setup/project-structure-template.md
Normal file
112
skills/python-project-setup/project-structure-template.md
Normal 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
|
||||
226
skills/python-project-setup/pyproject-toml-template.md
Normal file
226
skills/python-project-setup/pyproject-toml-template.md
Normal 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
|
||||
```
|
||||
332
skills/python-project-setup/readme-template.md
Normal file
332
skills/python-project-setup/readme-template.md
Normal 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
|
||||
54
skills/python-project-setup/vscode-settings-template.json
Normal file
54
skills/python-project-setup/vscode-settings-template.json
Normal 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
|
||||
}
|
||||
}
|
||||
111
skills/python-testing/SKILL.md
Normal file
111
skills/python-testing/SKILL.md
Normal 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
|
||||
447
skills/python-testing/pytest-configuration.md
Normal file
447
skills/python-testing/pytest-configuration.md
Normal 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)
|
||||
```
|
||||
Reference in New Issue
Block a user