From abf7b257164680ce2de3029231222c74a2fc16fe Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sun, 30 Nov 2025 09:00:19 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 15 + README.md | 3 + commands/python-setup.md | 355 +++++++++++++++++++ plugin.lock.json | 53 +++ skills/python-code-review/SKILL.md | 465 +++++++++++++++++++++++++ skills/python-project-setup/SKILL.md | 486 +++++++++++++++++++++++++++ 6 files changed, 1377 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 commands/python-setup.md create mode 100644 plugin.lock.json create mode 100644 skills/python-code-review/SKILL.md create mode 100644 skills/python-project-setup/SKILL.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..e24fca2 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "python-dev", + "description": "Modern Python development assistant with uv tooling, PEP8 standards, and project setup automation", + "version": "1.0.0", + "author": { + "name": "Tasanakorn Phaipool", + "email": "tasanakorn@gmail.com" + }, + "skills": [ + "./skills" + ], + "commands": [ + "./commands" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..26d7019 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# python-dev + +Modern Python development assistant with uv tooling, PEP8 standards, and project setup automation diff --git a/commands/python-setup.md b/commands/python-setup.md new file mode 100644 index 0000000..7a9021f --- /dev/null +++ b/commands/python-setup.md @@ -0,0 +1,355 @@ +You are a Python project setup assistant specializing in modern Python development practices with uv tooling. + +**IMPORTANT DEFAULTS - DO NOT ASK**: +- **Work in current directory** (don't create new folder) +- **Package name** from current folder name (auto-convert to valid identifier) +- **Python version** from current environment (detect with `python --version`) +- **No tests** by default (skip tests/ directory) +- **Minimal dependencies** (only ruff + mypy for dev) + +When this command is invoked, follow these steps: + +## Step 1: Auto-Detect Defaults + +Automatically detect without asking: +1. **Current directory** as project root +2. **Package name** from folder name (e.g., `my-app` → `my_app`) +3. **Python version** from environment: + ```bash + python --version # Use this version + ``` + +## Step 2: Ask Single Merged Question + +Ask ONE question that combines project type and libraries: + +``` +What type of project? (press Enter for CLI with click+rich) +[1] CLI with click+rich (default) +[2] CLI with argparse +[3] CLI with typer +[4] TUI with textual +[5] Generic Python Project +``` + +User can just press Enter to select [1] CLI with click+rich as default. + +## Step 3: Check Prerequisites + +Verify that `uv` is installed: +```bash +uv --version +``` + +If not installed, provide installation instructions: +- **macOS/Linux**: `curl -LsSf https://astral.sh/uv/install.sh | sh` +- **Windows**: `powershell -c "irm https://astral.sh/uv/install.ps1 | iex"` + +## Step 4: Skip - Question Already Asked + +(Project type and libraries were already selected in Step 2) + +## Step 5: Create Minimal Project Structure + +**Create in current directory (./), not in a new subfolder!** + +``` +./ # Current directory (project root) +├── src/ +│ └── package_name/ +│ ├── __init__.py # Package initialization +│ └── __main__.py # Entry point +├── pyproject.toml # Minimal configuration +├── README.md # Documentation +└── .gitignore # Git ignore patterns +``` + +**DO NOT create:** +- ❌ tests/ directory +- ❌ py.typed file +- ❌ .python-version file +- ❌ New project directory + +## Step 6: Generate Minimal pyproject.toml + +Create minimal pyproject.toml with: + +### [project] section: +- name (from package name) +- version = "0.1.0" +- description (from user, or empty string if skipped) +- authors (can use generic placeholder) +- readme = "README.md" +- requires-python = ">=X.Y" (from detected Python version) +- dependencies (only if CLI/TUI libraries selected, otherwise empty) + +### [project.optional-dependencies]: +```toml +dev = [ + "ruff>=0.1.0", + "mypy>=1.8.0", +] +# Note: No pytest - user can add later if needed +``` + +### [project.scripts] (for CLI/TUI applications): +```toml +[project.scripts] +project-name = "package_name.__main__:main" +``` + +### [build-system]: +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" +``` + +### [tool.ruff]: +```toml +[tool.ruff] +line-length = 88 +target-version = "py311" +select = ["E", "F", "I", "N", "W", "UP"] +``` + +### [tool.mypy]: +```toml +[tool.mypy] +python_version = "3.11" +strict = true +warn_return_any = true +warn_unused_configs = true +``` + +## Step 7: Create Entry Point + +Generate appropriate `__main__.py` based on project type: + +### For Library: +```python +"""Main entry point for package_name.""" + +def main() -> None: + """Execute the main program.""" + print("Hello from package_name!") + print("This is a library package.") + +if __name__ == "__main__": + main() +``` + +### For CLI Application (with click): +```python +"""Main entry point for package_name CLI.""" + +import click +from rich.console import Console + +console = Console() + +@click.group() +@click.version_option() +def main() -> None: + """Package name CLI application.""" + pass + +@main.command() +@click.option("--name", default="World", help="Name to greet") +def hello(name: str) -> None: + """Greet someone.""" + console.print(f"[bold green]Hello, {name}![/bold green]") + +if __name__ == "__main__": + main() +``` + +### For TUI Application (with textual): +```python +"""Main entry point for package_name TUI.""" + +from textual.app import App, ComposeResult +from textual.widgets import Header, Footer, Static + +class MainApp(App): + """A Textual TUI application.""" + + TITLE = "Package Name" + + def compose(self) -> ComposeResult: + yield Header() + yield Static("Welcome to Package Name!") + yield Footer() + +def main() -> None: + """Run the TUI application.""" + app = MainApp() + app.run() + +if __name__ == "__main__": + main() +``` + +## Step 8: Initialize with uv + +Provide the following commands (already in current directory): + +```bash +# Already in project directory (current folder) + +# Create virtual environment +uv venv + +# Sync dependencies from pyproject.toml +uv sync + +# Install project in editable mode +uv pip install -e . + +# Sync development dependencies +uv sync --group dev +``` + +## Step 9: Create README.md + +Generate a README with: +- Project title and description +- Installation instructions +- Usage examples +- Development setup +- Testing commands +- License information + +## Step 10: Create .gitignore + +Include patterns for: +``` +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +*.egg-info/ +.eggs/ + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# uv +uv.lock + +# OS +.DS_Store +Thumbs.db +``` + +## Step 11: Provide Next Steps + +Display a minimal summary: + +```markdown +## ✅ Python Project Setup Complete! + +### Project Directory +**Working in**: `./` (current directory) +**Package**: package_name +**Python**: [Detected version, e.g., 3.11+] + +### Created Structure +[Show directory tree relative to current directory] + +### Dependencies Installed +**Main:** +- [list dependencies, or "None - minimal setup" if empty] + +**Development:** +- ruff (linting) +- mypy (type checking) + +### Next Steps + +1. **Activate environment (optional, uv handles this):** + ```bash + source .venv/bin/activate # Linux/macOS + .venv\Scripts\activate # Windows + ``` + +2. **Run your application:** + ```bash + uv run python -m package_name + # or + uv run package-name + ``` + +3. **Lint code:** + ```bash + uv run ruff check . + uv run mypy src + ``` + +4. **Add dependencies when needed:** + ```bash + uv add package-name + uv add --dev package-name + ``` + +### Development Commands + +| Task | Command | +|------|---------| +| Add dependency | `uv add package-name` | +| Add dev dependency | `uv add --dev package-name` | +| Run script | `uv run python script.py` | +| Lint code | `uv run ruff check .` | +| Type check | `uv run mypy src` | + +### To Add Later (Optional) + +**Tests:** +```bash +mkdir tests +uv add --dev pytest pytest-cov +# Create tests/test_basic.py +``` + +Happy coding! 🐍 +``` + +## Guidelines + +**Be MINIMAL and FAST:** +- Use current directory (never create nested folders) +- Auto-detect Python version (don't ask) +- Derive package name from folder (don't ask) +- Skip tests by default (user adds when ready) +- **Ask ONE merged question** (project type + libraries combined) +- Default to CLI with click+rich if user presses Enter +- Provide clear, copy-pasteable commands +- Be friendly but concise +- If user has questions, answer thoroughly +- Adapt if user has specific requirements + +**Key Principles:** +- Work in `.` (current directory) +- Detect, don't ask (Python version, package name) +- Smart default: CLI with click+rich (most common use case) +- One question: project type + libraries combined +- User adds complexity as needed diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..27c95df --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,53 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:tasanakorn/cc-marketplace:plugins/python-dev", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "72de2ba427e5d8b5eec786fc3a61ad64a3e02322", + "treeHash": "e063ff3012266d547d5f21ca1b2d2f83c703546797562878dd29625d8edeeff6", + "generatedAt": "2025-11-28T10:28:35.623591Z", + "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": "python-dev", + "description": "Modern Python development assistant with uv tooling, PEP8 standards, and project setup automation", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "df968cd158233088015581ea638878f9bea60afaf54d1583b260b80e64d23453" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "2e801d60594a083497af044988759856d2bf0b5a03879fec43ea0af93e7f5786" + }, + { + "path": "commands/python-setup.md", + "sha256": "87cb836dd56ec13bbd3c2a6008152007b4c339fe63d80f8f381dda719e0b5494" + }, + { + "path": "skills/python-project-setup/SKILL.md", + "sha256": "6a1bfddfba023e2d4f04aed91f52c225443063fba68e16aad5ec9cddc37b3131" + }, + { + "path": "skills/python-code-review/SKILL.md", + "sha256": "c91e1f06cd5a7663cdfee9be35cf73afeeb954b3699aaeab587eb622601d46db" + } + ], + "dirSha256": "e063ff3012266d547d5f21ca1b2d2f83c703546797562878dd29625d8edeeff6" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/python-code-review/SKILL.md b/skills/python-code-review/SKILL.md new file mode 100644 index 0000000..0558cae --- /dev/null +++ b/skills/python-code-review/SKILL.md @@ -0,0 +1,465 @@ +--- +name: python-code-review +description: Reviews Python code for PEP8 compliance, type hints, modern best practices (Python 3.9+), and code quality. Detects anti-patterns, validates documentation, and provides severity-based recommendations. Integrates with modern tooling (ruff, mypy, uv). +--- + +# Python Code Review Skill + +A specialized skill for reviewing Python code with focus on PEP8 compliance, type hints, modern best practices, and code quality. + +## Overview + +This skill enables Claude to autonomously review Python code for compliance with modern Python standards, including PEP8 style guidelines, type hint coverage, proper structure, and common anti-patterns. It promotes clean, maintainable, and type-safe Python code. + +## Capabilities + +When activated, this skill provides: + +1. **PEP8 Compliance Review** + - Check naming conventions (snake_case, PascalCase) + - Verify line length (88 characters) + - Review whitespace and indentation + - Check import ordering and grouping + - Validate docstring presence and format + +2. **Type Hints Validation** + - Ensure all functions have type hints + - Check for proper return type annotations + - Validate use of modern type syntax (list[], dict[] over List[], Dict[]) + - Verify Optional[] vs None union types + - Check for Any types (discourage overuse) + +3. **Code Structure & Organization** + - Review module structure and imports + - Check for proper `__init__.py` usage + - Validate entry points (`__main__.py`) + - Review function/class organization + - Assess module coupling and cohesion + +4. **Best Practices Enforcement** + - Check for use of context managers (with statements) + - Validate exception handling + - Review string formatting (f-strings preferred) + - Check for proper constant definitions + - Assess use of comprehensions vs loops + +5. **Common Anti-Patterns Detection** + - Mutable default arguments + - Bare except clauses + - Using `global` keyword unnecessarily + - Poor variable naming + - Overly complex functions (high cyclomatic complexity) + +6. **Documentation Quality** + - Check for docstrings on public functions/classes + - Validate docstring format (Google/NumPy style) + - Review parameter documentation + - Check for return value documentation + - Assess example usage in docstrings + +## Usage + +This skill activates automatically when: +- User requests: "Review this Python code" +- User asks: "Check PEP8 compliance" +- User mentions: "Validate type hints" +- User wants: "Improve this Python code" +- Code review is requested for .py files +- User asks: "Is this code following best practices?" + +## Review Approach + +### 1. Initial Assessment +- Identify Python version being used +- Understand the code's purpose +- Determine if it's application code or library code +- Check project structure context + +### 2. PEP8 Compliance Check + +**Naming Conventions:** +- ✅ Functions/variables: `snake_case` +- ✅ Classes: `PascalCase` +- ✅ Constants: `UPPER_SNAKE_CASE` +- ✅ Private members: `_leading_underscore` +- ✅ Module names: `lowercase` or `snake_case` + +**Code Layout:** +- ✅ Line length: 88 characters (Black standard) +- ✅ Indentation: 4 spaces +- ✅ Blank lines: 2 before top-level definitions, 1 between methods +- ✅ Import order: stdlib → third-party → local +- ✅ One import per line (except from imports) + +### 3. Type Hints Review + +**Check for:** +```python +# ❌ Missing type hints +def process(data): + return data.upper() + +# ✅ Proper type hints +def process(data: str) -> str: + return data.upper() + +# ❌ Old-style typing (Python <3.9) +from typing import List, Dict +def get_items() -> List[Dict[str, int]]: + pass + +# ✅ Modern type syntax (Python 3.9+) +def get_items() -> list[dict[str, int]]: + pass + +# ❌ Overuse of Any +from typing import Any +def process(data: Any) -> Any: + pass + +# ✅ Specific types +def process(data: str | int) -> str: + return str(data) +``` + +### 4. Common Issues Detection + +**Mutable Default Arguments:** +```python +# ❌ Dangerous +def append_to(element: str, target: list[str] = []) -> list[str]: + target.append(element) + return target + +# ✅ Safe +def append_to(element: str, target: list[str] | None = None) -> list[str]: + if target is None: + target = [] + target.append(element) + return target +``` + +**Exception Handling:** +```python +# ❌ Bare except +try: + risky_operation() +except: + pass + +# ✅ Specific exception +try: + risky_operation() +except ValueError as e: + logger.error(f"Invalid value: {e}") + raise +``` + +**String Formatting:** +```python +# ❌ Old style +name = "World" +print("Hello %s" % name) +print("Hello {}".format(name)) + +# ✅ Modern f-strings +print(f"Hello {name}") +``` + +**Context Managers:** +```python +# ❌ Manual resource management +file = open("data.txt") +data = file.read() +file.close() + +# ✅ Context manager +with open("data.txt") as file: + data = file.read() +``` + +### 5. Code Quality Assessment + +**Function Complexity:** +- Functions should do one thing well +- Aim for <20 lines per function +- Cyclomatic complexity should be low (<10) +- Deep nesting (>3 levels) indicates need for refactoring + +**Example - Complex to Simple:** +```python +# ❌ Too complex +def process_user(user): + if user: + if user.active: + if user.email: + if "@" in user.email: + return user.email.lower() + return None + +# ✅ Simplified +def process_user(user: User | None) -> str | None: + if not user or not user.active or not user.email: + return None + + if "@" not in user.email: + return None + + return user.email.lower() +``` + +## Output Format + +Provide review results in this structured format: + +```markdown +## Python Code Review Results + +### Summary +[Brief overview of the code quality and main findings] + +### PEP8 Compliance: [PASS/FAIL/PARTIAL] +**Issues Found:** +- Line 15: Line too long (102 characters, limit 88) +- Line 23: Missing blank line after function definition +- Line 45: Import should be at top of file + +### Type Hints Coverage: [X%] +**Missing Type Hints:** +- Line 10: Function `process_data` missing return type +- Line 18: Parameter `config` missing type annotation +- Line 25: Using deprecated `List` instead of `list` + +**Recommendations:** +```python +# Current +def process_data(items, limit=10): + return items[:limit] + +# Improved +def process_data(items: list[str], limit: int = 10) -> list[str]: + return items[:limit] +``` + +### Code Quality Issues + +#### Critical 🔴 +- **Line 34**: Mutable default argument in `add_item(item, items=[])` +- **Line 56**: Bare except clause catching all exceptions + +#### Important 🟡 +- **Line 12**: Function complexity too high (15 branches) +- **Line 78**: Using `global` keyword - consider refactoring +- **Line 91**: Variable name `x` is not descriptive + +#### Minor 🔵 +- **Line 23**: Could use f-string instead of .format() +- **Line 45**: List comprehension would be more Pythonic + +### Best Practices Violations + +1. **Line 15-18: Manual file handling** + - **Current:** + ```python + f = open("data.txt") + data = f.read() + f.close() + ``` + - **Improved:** + ```python + with open("data.txt") as f: + data = f.read() + ``` + +2. **Line 34: Mutable default argument** + - **Impact**: Can cause bugs when function is called multiple times + - **Fix**: Use None as default, create new list inside function + +### Positive Aspects ✅ +- Consistent naming conventions throughout +- Good use of type hints in 80% of functions +- Proper docstrings on all public methods +- Clean import organization + +### Documentation Review +- ✅ All public functions have docstrings +- ✅ Docstrings follow Google style format +- ⚠️ Some docstrings missing return value description +- ⚠️ No examples in docstrings (consider adding for complex functions) + +### Modernization Suggestions +- Update to Python 3.10+ syntax (use `|` for unions instead of `Union`) +- Consider using `match/case` statement (Python 3.10+) for complex conditionals +- Replace `Dict`, `List` with `dict`, `list` (Python 3.9+) + +### Next Steps +1. Fix critical issues (mutable defaults, bare excepts) +2. Add missing type hints +3. Refactor complex functions (>15 lines) +4. Run automated tools: + ```bash + uv run ruff check . # Linting + uv run mypy . # Type checking + uv run ruff format . # Auto-formatting + ``` + +### Recommended Tools +- **ruff**: Fast linting and formatting (replaces black, flake8, isort) +- **mypy**: Static type checking +- **pytest**: Testing framework +- **coverage**: Code coverage analysis + +### Overall Assessment: [GOOD/NEEDS IMPROVEMENT/EXCELLENT] +[Brief summary and priority recommendations] +``` + +## Review Standards + +### PEP8 Checklist + +**Naming:** +- [ ] Functions and variables use snake_case +- [ ] Classes use PascalCase +- [ ] Constants use UPPER_SNAKE_CASE +- [ ] Private members start with underscore + +**Formatting:** +- [ ] Line length ≤ 88 characters +- [ ] 4 spaces for indentation (no tabs) +- [ ] 2 blank lines before class/function definitions +- [ ] 1 blank line between methods + +**Imports:** +- [ ] Grouped: stdlib → third-party → local +- [ ] Alphabetically sorted within groups +- [ ] No wildcard imports (`from module import *`) +- [ ] Unused imports removed + +### Type Hints Standards + +**Required:** +```python +# All function parameters +def func(name: str, age: int) -> None: + pass + +# Return types (even None) +def get_data() -> dict[str, Any]: + pass + +# Class attributes +class User: + name: str + age: int + + def __init__(self, name: str, age: int) -> None: + self.name = name + self.age = age +``` + +**Modern Syntax (Python 3.9+):** +- Use `list[]` not `List[]` +- Use `dict[]` not `Dict[]` +- Use `tuple[]` not `Tuple[]` +- Use `set[]` not `Set[]` +- Use `|` not `Union[]` (Python 3.10+) + +### Documentation Standards + +**Google Style Docstrings:** +```python +def function_name(param1: str, param2: int) -> bool: + """Brief description of function. + + Longer description explaining what the function does, + its behavior, and any important details. + + Args: + param1: Description of param1 + param2: Description of param2 + + Returns: + Description of return value + + Raises: + ValueError: When param2 is negative + + Example: + >>> function_name("test", 5) + True + """ + pass +``` + +## Best Practices to Promote + +1. **Use type hints everywhere** - Improves IDE support and catches bugs early +2. **Prefer f-strings** - More readable than format() or % +3. **Use context managers** - For file handling, locks, connections +4. **Write small functions** - Each function should do one thing well +5. **Use comprehensions** - More Pythonic than loops for simple transformations +6. **Avoid global state** - Pass dependencies explicitly +7. **Use dataclasses** - For data containers (Python 3.7+) +8. **Use pathlib** - Instead of os.path for file operations +9. **Use enums** - For fixed sets of constants +10. **Write docstrings** - For all public APIs + +## Common Refactoring Patterns + +### Replace Loop with Comprehension +```python +# ❌ Before +result = [] +for item in items: + if item.active: + result.append(item.name) + +# ✅ After +result = [item.name for item in items if item.active] +``` + +### Use Dataclass +```python +# ❌ Before +class User: + def __init__(self, name, email, age): + self.name = name + self.email = email + self.age = age + +# ✅ After +from dataclasses import dataclass + +@dataclass +class User: + name: str + email: str + age: int +``` + +### Use Pathlib +```python +# ❌ Before +import os +path = os.path.join("data", "file.txt") +if os.path.exists(path): + with open(path) as f: + data = f.read() + +# ✅ After +from pathlib import Path +path = Path("data") / "file.txt" +if path.exists(): + data = path.read_text() +``` + +## Integration + +This skill works seamlessly with: +- Code review workflows +- Pull request reviews +- Refactoring tasks +- Code quality improvement projects +- Pre-commit validation +- Migration to modern Python versions +- Type hint adoption projects diff --git a/skills/python-project-setup/SKILL.md b/skills/python-project-setup/SKILL.md new file mode 100644 index 0000000..c5a2289 --- /dev/null +++ b/skills/python-project-setup/SKILL.md @@ -0,0 +1,486 @@ +--- +name: python-project-setup +description: Sets up modern Python projects with uv tooling, src layout, and PEP8 standards. Handles both new and existing projects, presents interactive library selection for CLI/TUI apps, generates pyproject.toml, and provides complete scaffolding with type hints and proper structure. +--- + +# Python Project Setup Skill + +A specialized skill for setting up modern Python projects using uv tooling, best practices, and standardized project structures. + +## Overview + +This skill enables Claude to autonomously set up Python projects following modern best practices. It promotes the use of `uv` (the fast Python package manager), enforces PEP8 standards, type hints, and proper project structure with `src` layout. + +## Capabilities + +When activated, this skill provides: + +1. **Modern Tooling with uv** + - Use `uv` instead of pip/python directly + - Initialize virtual environments: `uv venv` + - Manage dependencies: `uv add`, `uv remove` + - Sync dependencies: `uv sync` + - Run scripts: `uv run` + +2. **Project Structure Detection & Setup** + - Detect if project is new or existing + - Analyze current structure and adapt recommendations + - Promote `src/package_name` layout + - Create proper `__init__.py` files + - Setup `__main__.py` entry points + +3. **pyproject.toml Management** + - Generate modern pyproject.toml + - Configure project metadata + - Setup dependencies and dev dependencies + - Include tool configurations (ruff, mypy, pytest) + - Define entry points for CLI applications + +4. **Library Selection** + - Present interactive menu for library choices + - **CLI applications**: click (commands), rich (output), inquirer (interactive prompts) + - **TUI applications**: textual (framework), rich (rendering) + - **Pure libraries**: minimal dependencies + - Smart recommendations based on project type + +5. **Standards Enforcement** + - PEP8 compliance via ruff + - Type hints for all functions/methods + - Proper docstring formats (Google/NumPy style) + - Follow PEP8 and modern Python standards + +## Usage + +This skill activates automatically when: +- User requests: "Create a new Python project" +- User asks: "Setup Python project structure" +- User mentions: "Initialize Python package" +- User wants to: "Migrate to uv" +- Claude detects Python project initialization +- pyproject.toml creation or modification is discussed + +**Automatic Defaults**: +- Uses current directory as project root +- Derives package name from directory name +- Detects and uses current Python version +- No tests (user can add later) +- Minimal dependencies by default + +**Only ONE Question**: +- Project type + libraries combined (default: minimal) + +## Project Setup Approach + +### For New Projects + +**IMPORTANT**: Always work in the current directory as the project root. + +1. **Gather Requirements** + - Package name (derive from current directory name by default) + - **Ask ONE merged question**: Project type + libraries combined: + ``` + What type of project? (press Enter for CLI with click+rich) + [1] CLI with click+rich (default) + [2] CLI with argparse + [3] CLI with typer + [4] TUI with textual + [5] Generic Python Project + ``` + - **Don't ask about tests** - skip by default + +2. **Assume Current Directory & Python Version** + - **Use current folder as project root** (don't create new directory) + - Derive package name from current folder name (convert to valid Python identifier) + - Example: `my-awesome-app/` → package name: `my_awesome_app` + - **Detect current Python version** and use as project requirement + - Example: `python --version` → `Python 3.11.5` → `requires-python = ">=3.11"` + +3. **Check Environment** + ```bash + # Detect current Python version + python --version # Use this as the project's Python requirement + + # Verify uv is installed + uv --version + + # If not installed, provide instructions: + # macOS/Linux: curl -LsSf https://astral.sh/uv/install.sh | sh + # Windows: powershell -c "irm https://astral.sh/uv/install.ps1 | iex" + ``` + +4. **Create Minimal Project Structure in Current Directory** + ``` + ./ # Current directory (project root) + ├── src/ + │ └── package_name/ + │ ├── __init__.py + │ └── __main__.py # Entry point + ├── pyproject.toml # Minimal config + ├── README.md + └── .gitignore + ``` + + **Note**: No tests/, no .python-version - keep it minimal! + +5. **Skip Tests by Default** + - Do NOT ask about tests + - Do NOT create tests/ directory + - Do NOT include pytest in dev dependencies + - User can add tests later if needed + +6. **Generate Minimal pyproject.toml** + ```toml + [project] + name = "package-name" + version = "0.1.0" + description = "Project description" + authors = [ + {name = "Author Name", email = "author@example.com"} + ] + readme = "README.md" + requires-python = ">=3.11" # Use detected Python version (e.g., 3.11, 3.12, etc.) + dependencies = [ + # Based on library selection + ] + + [project.optional-dependencies] + dev = [ + "ruff>=0.1.0", + "mypy>=1.8.0", + ] + # Note: No pytest by default - add when needed + + [project.scripts] + package-name = "package_name.__main__:main" + + [build-system] + requires = ["hatchling"] + build-backend = "hatchling.build" + + [tool.ruff] + line-length = 88 + target-version = "py311" + select = ["E", "F", "I", "N", "W", "UP"] + + [tool.mypy] + python_version = "3.11" + strict = true + warn_return_any = true + warn_unused_configs = true + + [tool.pytest.ini_options] + testpaths = ["tests"] + python_files = ["test_*.py"] + ``` + +8. **Initialize with uv in Current Directory** + ```bash + # Already in project directory (current folder) + + # Create virtual environment + uv venv + + # Sync dependencies from pyproject.toml + uv sync + + # Add project in editable mode + uv pip install -e . + + # Add development dependencies (includes pytest if tests opted in) + uv sync --group dev + ``` + +9. **Create Entry Point Examples** + + For `src/package_name/__main__.py`: + ```python + """Main entry point for package_name.""" + + def main() -> None: + """Execute the main program.""" + print("Hello from package_name!") + + if __name__ == "__main__": + main() + ``` + + For CLI apps with click: + ```python + """Main entry point for package_name CLI.""" + + import click + from rich.console import Console + + console = Console() + + @click.group() + @click.version_option() + def main() -> None: + """Package name CLI application.""" + pass + + @main.command() + @click.option("--name", default="World", help="Name to greet") + def hello(name: str) -> None: + """Greet someone.""" + console.print(f"[bold green]Hello, {name}![/bold green]") + + if __name__ == "__main__": + main() + ``` + +### For Existing Projects + +**IMPORTANT**: Always work in the current directory, don't create subdirectories. + +1. **Analyze Current Directory Structure** + - Check for setup.py, requirements.txt, or pyproject.toml + - Identify current package structure + - Assess if src layout is used + - **Detect existing tests/** directory + +2. **Detect Context** + - Is uv already being used? + - What's the current dependency management approach? + - Are there existing entry points? + - **Are tests already present?** (skip test skeleton question if yes) + +3. **Skip Tests Question** + - Do NOT ask about tests for existing projects + - User can add tests manually if needed + +4. **Provide Migration Path** + ```bash + # Already in project directory (current folder) + + # Convert requirements.txt to pyproject.toml + # Create pyproject.toml with [project.dependencies] + + # Initialize uv for existing project + uv venv + + # Import existing requirements + uv pip install -r requirements.txt + + # Generate lock file + uv sync + ``` + +5. **Recommend Structure Improvements** + - Suggest moving to src layout if not present + - Identify missing __init__.py files + - Recommend adding __main__.py if needed + - Suggest adding type hints if missing + +6. **Adapt, Don't Force** + - Respect existing conventions if reasonable + - Provide gradual migration suggestions + - Explain benefits of each recommendation + +## Output Format + +Provide setup results in this format: + +```markdown +## Python Project Setup Complete + +### Project Directory +**Working in**: `./` (current directory) +**Package name**: `package_name` + +### Project Structure +[Show created directory tree relative to current directory] + +### Configuration +- **Python version**: [Detected from current environment, e.g., 3.11+] +- **Package manager**: uv +- **Layout**: src layout +- **Entry point**: src/package_name/__main__.py +- **Tests**: Not included (add later if needed) + +### Dependencies Installed +**Main dependencies:** +- [list dependencies] + +**Development dependencies:** +- ruff (linting) +- mypy (type checking) + +### Next Steps +1. Activate virtual environment: + \`\`\`bash + source .venv/bin/activate # Linux/macOS + .venv\\Scripts\\activate # Windows + \`\`\` + +2. Run your application: + \`\`\`bash + uv run python -m package_name + # or + uv run package-name + \`\`\` + +3. Add new dependencies: + \`\`\`bash + uv add package-name + \`\`\` + +4. Lint code: + \`\`\`bash + uv run ruff check . + uv run mypy src + \`\`\` + +### Development Commands +- Add dependency: `uv add package-name` +- Add dev dependency: `uv add --dev package-name` +- Remove dependency: `uv remove package-name` +- Update dependencies: `uv sync` +- Run script: `uv run python script.py` +``` + +## Standards Enforced + +### Always Use uv Commands +- ❌ `pip install package` +- ✅ `uv add package` + +- ❌ `pip install -r requirements.txt` +- ✅ `uv sync` + +- ❌ `python script.py` +- ✅ `uv run python script.py` + +- ❌ `python -m venv .venv` +- ✅ `uv venv` + +### Project Structure Standards +``` +src/package_name/ # Use src layout +├── __init__.py # Package marker (can be empty or contain version) +├── __main__.py # Entry point with main() function +├── module1.py # Application modules +└── module2.py +``` + +### Code Standards +- All functions must have type hints +- Use `"""Docstrings"""` for all public functions/classes +- Follow PEP8 (enforced by ruff) +- Line length: 88 characters (Black standard) +- Use absolute imports from package root + +### Example Type-Hinted Code +```python +from typing import Optional + +def process_data( + input_data: list[str], + max_items: int = 10, + filter_empty: bool = True +) -> dict[str, int]: + """Process input data and return statistics. + + Args: + input_data: List of strings to process + max_items: Maximum number of items to process + filter_empty: Whether to filter out empty strings + + Returns: + Dictionary with processing statistics + """ + result: dict[str, int] = {} + # Implementation + return result +``` + +## Library Recommendations + +### For CLI Applications +```toml +dependencies = [ + "click>=8.1.0", # Command-line interface framework + "rich>=13.7.0", # Beautiful terminal output + "inquirer>=3.2.0", # Interactive prompts +] +``` + +### For TUI Applications +```toml +dependencies = [ + "textual>=0.47.0", # Modern TUI framework + "rich>=13.7.0", # Rendering engine +] +``` + +### For Libraries +```toml +dependencies = [ + # Only essential dependencies + # Keep it minimal +] +``` + +## Best Practices + +1. **Work in current directory** - Don't create nested project folders +2. **Use current Python version** - Detect from environment, don't ask +3. **Ask one merged question** - Project type + libraries combined +4. **Start with minimal dependencies** - Add more as needed +5. **Always include type hints** - Helps with IDE support and catches bugs +6. **Use src layout** - Prevents import issues and packaging problems +7. **Pin major versions only** - e.g., `>=8.1.0` not `==8.1.0` +8. **Separate dev dependencies** - Use `[project.optional-dependencies]` +9. **Document with docstrings** - Every public function and class +10. **Don't ask about tests** - Skip by default, users add when ready +11. **Use ruff for linting** - Fast, comprehensive, replaces flake8/isort/black + +## Common Patterns + +### CLI Application with Click + Rich +```python +import click +from rich.console import Console +from rich.table import Table + +console = Console() + +@click.command() +@click.argument("name") +@click.option("--count", default=1, help="Number of greetings") +def greet(name: str, count: int) -> None: + """Greet NAME COUNT times.""" + for _ in range(count): + console.print(f"[bold blue]Hello, {name}![/bold blue]") +``` + +### TUI Application with Textual +```python +from textual.app import App, ComposeResult +from textual.widgets import Header, Footer, Button + +class MyApp(App): + """A simple Textual application.""" + + def compose(self) -> ComposeResult: + yield Header() + yield Button("Click me!", id="btn") + yield Footer() + + def on_button_pressed(self, event: Button.Pressed) -> None: + """Handle button press.""" + self.notify("Button clicked!") + +if __name__ == "__main__": + app = MyApp() + app.run() +``` + +## Integration + +This skill works seamlessly with: +- New Python project creation +- Existing project modernization +- Migration from pip to uv +- Package structure refactoring +- Dependency management tasks