Skill v1.0.0
currentTrusted Publisher100/100name: python-standards description: Python coding standards for Amplifier including type hints, async patterns, error handling, and formatting. Use when writing Python code for Amplifier modules. version: 1.0.0 license: MIT metadata: category: development complexity: low
Python Coding Standards
Type Hints
ALL functions must have complete type hints:
from typing import Anyasync def process_data(items: list[str], config: dict[str, Any]) -> dict[str, Any]:"""Process data items with configuration."""results = {}for item in items:results[item] = await transform(item, config)return results
Include type hints for self:
class MyClass:def __init__(self: "MyClass", name: str) -> None:self.name = nameasync def process(self: "MyClass") -> str:return f"Processing {self.name}"
Async Patterns
All I/O operations must be async:
# Goodasync def read_file(path: Path) -> str:content = path.read_text() # For now, sync is OKreturn content# Better (when using async libraries)async def read_file(path: Path) -> str:async with aiofiles.open(path) as f:return await f.read()
Use asyncio.gather for parallel operations:
async def process_files(files: list[Path]) -> list[dict]:tasks = [process_file(f) for f in files]return await asyncio.gather(*tasks)
Error Handling
Return errors, don't raise:
from amplifier_core import ToolResultasync def execute(self: "MyTool", input: dict[str, Any]) -> ToolResult:"""Execute tool operation."""try:result = await self._process(input)return ToolResult(success=True, output=result)except ValueError as e:logger.error(f"Validation error: {e}")return ToolResult(success=False, error={"message": str(e)})
Provide clear error messages:
# Goodreturn ToolResult(success=False,error={"message": f"File not found: {path}"})# Badreturn ToolResult(success=False,error={"message": "Error"})
Formatting
Line length: 120 characters
Import organization:
# Standard libraryimport asyncioimport loggingfrom pathlib import Pathfrom typing import Any# Third-partyimport yamlfrom pydantic import BaseModel# Local/Amplifierfrom amplifier_core import ModuleCoordinator, ToolResult
Files must end with newline - Add blank line at EOF
Use ruff for formatting:
uv run ruff format .uv run ruff check . --fix
Dependencies
Use uv for dependency management:
# Add dependencycd amplifier-module-tool-mytooluv add package-name# Add dev dependencyuv add --dev pytest ruff pyright
Never manually edit pyproject.toml dependencies - Use uv add
Testing
Test behavior at protocol level:
import pytestfrom amplifier_core.testing import TestCoordinator@pytest.mark.asyncioasync def test_tool_basic():"""Test basic tool functionality."""coordinator = TestCoordinator()# Mount moduleawait mount(coordinator, {"timeout": 10})# Get and testtool = coordinator.get("tools", "my-tool")result = await tool.execute({"param": "value"})assert result.successassert "expected" in result.output
Test pyramid: 60% unit, 30% integration, 10% end-to-end
Common Pitfalls
Don't use blocking I/O
# Badcontent = requests.get(url).text# Goodasync with aiohttp.ClientSession() as session:async with session.get(url) as response:content = await response.text()
Don't modify module internals from outside
# Badtool._internal_state = new_value# Goodawait tool.execute({"operation": "update", "value": new_value})
Don't put logic in mount()
# Badasync def mount(coordinator, config):tool = MyTool()await tool.initialize_database() # Heavy logicawait coordinator.mount("tools", tool)# Goodasync def mount(coordinator, config):tool = MyTool(config) # Light initialization onlyawait coordinator.mount("tools", tool)# Heavy logic happens in execute(), not mount()
Remember
- Run
make checkbefore committing - Keep modules focused and simple
- Document public interfaces
- Test at the protocol level