From 833eac73ea671b84f995bd666cf827a40e0d2030 Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sun, 30 Nov 2025 08:30:04 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 20 + README.md | 3 + agents/python-project-setup.md | 376 +++++++++++++++ commands/py-deps.md | 34 ++ commands/py-init.md | 51 ++ commands/py-lint.md | 33 ++ commands/py-test.md | 30 ++ hooks/hooks.json | 24 + plugin.lock.json | 109 +++++ skills/python-code-quality/SKILL.md | 89 ++++ .../python-code-quality/mypy-configuration.md | 374 +++++++++++++++ .../python-code-quality/ruff-configuration.md | 229 +++++++++ skills/python-project-setup/SKILL.md | 76 +++ .../gitignore-template.md | 209 ++++++++ .../project-structure-template.md | 112 +++++ .../pyproject-toml-template.md | 226 +++++++++ .../python-project-setup/readme-template.md | 332 +++++++++++++ .../vscode-settings-template.json | 54 +++ skills/python-testing/SKILL.md | 111 +++++ skills/python-testing/pytest-configuration.md | 447 ++++++++++++++++++ 20 files changed, 2939 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 agents/python-project-setup.md create mode 100644 commands/py-deps.md create mode 100644 commands/py-init.md create mode 100644 commands/py-lint.md create mode 100644 commands/py-test.md create mode 100644 hooks/hooks.json create mode 100644 plugin.lock.json create mode 100644 skills/python-code-quality/SKILL.md create mode 100644 skills/python-code-quality/mypy-configuration.md create mode 100644 skills/python-code-quality/ruff-configuration.md create mode 100644 skills/python-project-setup/SKILL.md create mode 100644 skills/python-project-setup/gitignore-template.md create mode 100644 skills/python-project-setup/project-structure-template.md create mode 100644 skills/python-project-setup/pyproject-toml-template.md create mode 100644 skills/python-project-setup/readme-template.md create mode 100644 skills/python-project-setup/vscode-settings-template.json create mode 100644 skills/python-testing/SKILL.md create mode 100644 skills/python-testing/pytest-configuration.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..a6990e8 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -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" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..088c169 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# pythonic + +Python project setup and development workflows following modern best practices with uv, ruff, pytest, and FastAPI diff --git a/agents/python-project-setup.md b/agents/python-project-setup.md new file mode 100644 index 0000000..bbed1e1 --- /dev/null +++ b/agents/python-project-setup.md @@ -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 + cd + ``` + +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: +``` +/ +├── .vscode/ +├── src// +│ ├── __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//main.py`) + ```python + """Main module for .""" + + def main() -> None: + """Main entry point.""" + print("Hello from !") + + if __name__ == "__main__": + main() + ``` + +2. **Create Initial Test** (`tests/test_main.py`) + ```python + """Tests for main module.""" + from .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 + + # 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 + uv add --dev + ``` + +## 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 +``` + +### Version Conflicts +If Python version is not available: +```bash +# Install with pyenv +pyenv install +``` + +## 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//api/` directory +- Create `src//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 # Add dependencies +``` diff --git a/commands/py-deps.md b/commands/py-deps.md new file mode 100644 index 0000000..da2dbdd --- /dev/null +++ b/commands/py-deps.md @@ -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 ` + - For development: `uv add --dev ` + - Confirm package was added to `pyproject.toml` + +2. **Update Dependencies** + - Run `uv sync` to sync all dependencies + - Update specific package: `uv add @latest` + - Report outdated packages if requested + +3. **Remove Dependencies** + - Run `uv remove ` 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 diff --git a/commands/py-init.md b/commands/py-init.md new file mode 100644 index 0000000..283a49b --- /dev/null +++ b/commands/py-init.md @@ -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 ` to create the project + - Create `.python-version` file for pyenv compatibility + - Initialize git repository if not already present + +2. **Directory Structure** + - Create `src//` 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 diff --git a/commands/py-lint.md b/commands/py-lint.md new file mode 100644 index 0000000..667e74a --- /dev/null +++ b/commands/py-lint.md @@ -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 diff --git a/commands/py-test.md b/commands/py-test.md new file mode 100644 index 0000000..c5f1af2 --- /dev/null +++ b/commands/py-test.md @@ -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 diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..cc3cb9d --- /dev/null +++ b/hooks/hooks.json @@ -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" + } + } +} diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..40e50da --- /dev/null +++ b/plugin.lock.json @@ -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": [] + } +} \ No newline at end of file diff --git a/skills/python-code-quality/SKILL.md b/skills/python-code-quality/SKILL.md new file mode 100644 index 0000000..c26985e --- /dev/null +++ b/skills/python-code-quality/SKILL.md @@ -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 diff --git a/skills/python-code-quality/mypy-configuration.md b/skills/python-code-quality/mypy-configuration.md new file mode 100644 index 0000000..263446b --- /dev/null +++ b/skills/python-code-quality/mypy-configuration.md @@ -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"] +``` diff --git a/skills/python-code-quality/ruff-configuration.md b/skills/python-code-quality/ruff-configuration.md new file mode 100644 index 0000000..ea29c99 --- /dev/null +++ b/skills/python-code-quality/ruff-configuration.md @@ -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 diff --git a/skills/python-project-setup/SKILL.md b/skills/python-project-setup/SKILL.md new file mode 100644 index 0000000..c14e607 --- /dev/null +++ b/skills/python-project-setup/SKILL.md @@ -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//` 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 + +# 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 diff --git a/skills/python-project-setup/gitignore-template.md b/skills/python-project-setup/gitignore-template.md new file mode 100644 index 0000000..2f9e812 --- /dev/null +++ b/skills/python-project-setup/gitignore-template.md @@ -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 diff --git a/skills/python-project-setup/project-structure-template.md b/skills/python-project-setup/project-structure-template.md new file mode 100644 index 0000000..de7f867 --- /dev/null +++ b/skills/python-project-setup/project-structure-template.md @@ -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 diff --git a/skills/python-project-setup/pyproject-toml-template.md b/skills/python-project-setup/pyproject-toml-template.md new file mode 100644 index 0000000..12b99e9 --- /dev/null +++ b/skills/python-project-setup/pyproject-toml-template.md @@ -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 +``` diff --git a/skills/python-project-setup/readme-template.md b/skills/python-project-setup/readme-template.md new file mode 100644 index 0000000..6867d43 --- /dev/null +++ b/skills/python-project-setup/readme-template.md @@ -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 diff --git a/skills/python-project-setup/vscode-settings-template.json b/skills/python-project-setup/vscode-settings-template.json new file mode 100644 index 0000000..6b52833 --- /dev/null +++ b/skills/python-project-setup/vscode-settings-template.json @@ -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 + } +} diff --git a/skills/python-testing/SKILL.md b/skills/python-testing/SKILL.md new file mode 100644 index 0000000..d5770bd --- /dev/null +++ b/skills/python-testing/SKILL.md @@ -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 diff --git a/skills/python-testing/pytest-configuration.md b/skills/python-testing/pytest-configuration.md new file mode 100644 index 0000000..2283479 --- /dev/null +++ b/skills/python-testing/pytest-configuration.md @@ -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) +```