# Skill Examples This file contains complete, working examples of well-structured skills across different domains. ## Example 1: Python Testing Skill ### Structure ``` python-testing-skill/ ├── SKILL.md └── test-templates/ ├── pytest-basic.py └── pytest-advanced.py ``` ### SKILL.md ```markdown --- name: Python Testing with pytest description: Create comprehensive Python tests using pytest with fixtures, parametrization, and mocking. Use when writing unit tests, integration tests, or setting up test infrastructure for Python projects. --- ## When to Use This Skill Use this skill when: - Writing unit tests for Python functions and classes - Creating integration tests for Python applications - Setting up pytest configuration and fixtures - Implementing test parametrization for multiple scenarios - Mocking external dependencies in tests Do NOT use this skill for: - Testing non-Python code - End-to-end browser testing (use Playwright skill instead) - Load testing or performance benchmarking ## Quick Start Basic test structure: ```python import pytest from myapp import add_numbers def test_add_numbers(): result = add_numbers(2, 3) assert result == 5 ``` Run tests: ```bash pytest tests/ -v ``` ## Core Workflows ### Workflow 1: Writing Unit Tests 1. Create a test file matching your source file: `test_module.py` for `module.py` 2. Import the code to test and pytest 3. Write test functions starting with `test_` 4. Use assert statements for validation 5. Run pytest from project root **Example:** ```python # test_calculator.py import pytest from calculator import Calculator def test_addition(): calc = Calculator() assert calc.add(2, 3) == 5 assert calc.add(-1, 1) == 0 assert calc.add(0, 0) == 0 def test_division_by_zero(): calc = Calculator() with pytest.raises(ValueError, match="Cannot divide by zero"): calc.divide(10, 0) ``` ### Workflow 2: Using Fixtures 1. Create fixtures for common test setup 2. Use `@pytest.fixture` decorator 3. Accept fixtures as test function parameters 4. Fixtures run automatically before tests **Example:** ```python import pytest from database import Database @pytest.fixture def db(): """Provide a test database instance""" database = Database(":memory:") database.setup() yield database database.teardown() def test_create_user(db): user = db.create_user("alice", "alice@example.com") assert user.name == "alice" assert user.email == "alice@example.com" def test_query_user(db): db.create_user("bob", "bob@example.com") user = db.query_user("bob") assert user is not None ``` ### Workflow 3: Parametrized Tests 1. Use `@pytest.mark.parametrize` decorator 2. Provide parameter names and test cases 3. Test function runs once per parameter set **Example:** ```python import pytest from validators import validate_email @pytest.mark.parametrize("email,expected", [ ("user@example.com", True), ("user@domain.co.uk", True), ("invalid@", False), ("@example.com", False), ("no-at-sign.com", False), ("", False), ]) def test_email_validation(email, expected): assert validate_email(email) == expected ``` ### Workflow 4: Mocking External Dependencies 1. Import `unittest.mock` or use `pytest-mock` 2. Use `mocker.patch()` to replace dependencies 3. Configure mock return values or side effects 4. Verify mock interactions **Example:** ```python import pytest from unittest.mock import Mock from weather_app import get_weather def test_get_weather(mocker): # Mock the external API call mock_api = mocker.patch('weather_app.weather_api.fetch') mock_api.return_value = { "temperature": 72, "conditions": "sunny" } result = get_weather("San Francisco") assert result["temperature"] == 72 assert result["conditions"] == "sunny" mock_api.assert_called_once_with("San Francisco") ``` ## Test Organization ### Project Structure ``` myproject/ ├── src/ │ └── myapp/ │ ├── __init__.py │ ├── core.py │ └── utils.py ├── tests/ │ ├── __init__.py │ ├── conftest.py # Shared fixtures │ ├── test_core.py │ └── test_utils.py └── pyproject.toml # pytest configuration ``` ### conftest.py for Shared Fixtures ```python import pytest from myapp import create_app @pytest.fixture(scope="session") def app(): """Create application for testing""" app = create_app(testing=True) return app @pytest.fixture def client(app): """Test client for making requests""" return app.test_client() ``` ## Configuration ### pyproject.toml ```toml [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_functions = ["test_*"] addopts = [ "-v", "--strict-markers", "--cov=myapp", "--cov-report=term-missing", ] markers = [ "slow: marks tests as slow", "integration: marks tests as integration tests", ] ``` ## Coverage Goals Aim for: - 80%+ code coverage for business logic - 100% coverage for critical paths (auth, payments, data integrity) - Edge cases and error conditions tested - Integration tests for key workflows Check coverage: ```bash pytest --cov=myapp --cov-report=html open htmlcov/index.html ``` ## Common Pitfalls ### Issue: Tests Pass Locally but Fail in CI **Solution:** - Use fixtures to avoid state pollution between tests - Don't rely on file system state or specific paths - Mock time-dependent functionality - Set explicit random seeds for reproducibility ### Issue: Slow Test Suite **Solution:** - Use `@pytest.mark.slow` for slow tests, run separately - Mock external API calls instead of making real requests - Use in-memory databases for tests - Run fast unit tests before slow integration tests ### Issue: Fixtures Not Running **Solution:** - Ensure fixture name matches parameter name exactly - Check fixture scope (function/class/module/session) - Verify conftest.py is in correct location ## Advanced Techniques ### Async Testing ```python import pytest @pytest.mark.asyncio async def test_async_function(): result = await async_fetch_data() assert result["status"] == "success" ``` ### Testing Exceptions with Context ```python def test_invalid_input(): with pytest.raises(ValueError) as exc_info: process_data(invalid_input) assert "expected format" in str(exc_info.value) ``` ### Temporary File Testing ```python def test_file_processing(tmp_path): # tmp_path is a pytest fixture providing a temporary directory test_file = tmp_path / "test.txt" test_file.write_text("test content") result = process_file(test_file) assert result.success ``` ``` --- ## Example 2: API Integration Skill ### SKILL.md ```markdown --- name: REST API Integration description: Design and implement RESTful API integrations with proper error handling, authentication, and rate limiting. Use when building API clients or integrating third-party services. --- ## When to Use This Skill Use this skill when: - Integrating third-party REST APIs into your application - Building API client libraries - Implementing API authentication flows (OAuth, JWT, API keys) - Handling rate limiting and retries - Creating robust error handling for API calls Do NOT use this skill for: - GraphQL APIs (different query paradigm) - gRPC or WebSocket connections - Building API servers (use framework-specific skills) ## Quick Start Basic API client structure: ```python import requests class APIClient: def __init__(self, base_url, api_key): self.base_url = base_url self.session = requests.Session() self.session.headers.update({ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }) def get(self, endpoint): response = self.session.get(f"{self.base_url}{endpoint}") response.raise_for_status() return response.json() ``` ## Core Workflows ### Workflow 1: Implementing Authentication **API Key Authentication:** ```python class APIKeyClient: def __init__(self, api_key): self.headers = {"X-API-Key": api_key} def request(self, method, url, **kwargs): kwargs.setdefault('headers', {}).update(self.headers) return requests.request(method, url, **kwargs) ``` **OAuth 2.0 Flow:** ```python from requests_oauthlib import OAuth2Session class OAuthClient: def __init__(self, client_id, client_secret, redirect_uri): self.client_id = client_id self.client_secret = client_secret self.redirect_uri = redirect_uri self.session = None def get_authorization_url(self, authorization_base_url): oauth = OAuth2Session(self.client_id, redirect_uri=self.redirect_uri) authorization_url, state = oauth.authorization_url(authorization_base_url) return authorization_url, state def fetch_token(self, token_url, authorization_response): oauth = OAuth2Session(self.client_id, redirect_uri=self.redirect_uri) token = oauth.fetch_token( token_url, authorization_response=authorization_response, client_secret=self.client_secret ) self.session = oauth return token ``` ### Workflow 2: Error Handling and Retries ```python import time from requests.adapters import HTTPAdapter from requests.packages.urllib3.util.retry import Retry class RobustAPIClient: def __init__(self, base_url, api_key, max_retries=3): self.base_url = base_url self.session = requests.Session() # Configure retry strategy retry_strategy = Retry( total=max_retries, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504], allowed_methods=["GET", "POST", "PUT", "DELETE"] ) adapter = HTTPAdapter(max_retries=retry_strategy) self.session.mount("http://", adapter) self.session.mount("https://", adapter) self.session.headers.update({ "Authorization": f"Bearer {api_key}" }) def request(self, method, endpoint, **kwargs): url = f"{self.base_url}{endpoint}" try: response = self.session.request(method, url, **kwargs) response.raise_for_status() return response.json() except requests.exceptions.HTTPError as e: if e.response.status_code == 401: raise AuthenticationError("Invalid or expired API key") elif e.response.status_code == 404: raise NotFoundError(f"Resource not found: {endpoint}") elif e.response.status_code == 429: raise RateLimitError("Rate limit exceeded") else: raise APIError(f"API request failed: {e}") except requests.exceptions.RequestException as e: raise APIError(f"Network error: {e}") class APIError(Exception): pass class AuthenticationError(APIError): pass class NotFoundError(APIError): pass class RateLimitError(APIError): pass ``` ### Workflow 3: Rate Limiting ```python import time from threading import Lock class RateLimiter: def __init__(self, calls_per_second): self.calls_per_second = calls_per_second self.min_interval = 1.0 / calls_per_second self.last_call = 0 self.lock = Lock() def __call__(self, func): def wrapper(*args, **kwargs): with self.lock: elapsed = time.time() - self.last_call if elapsed < self.min_interval: time.sleep(self.min_interval - elapsed) self.last_call = time.time() return func(*args, **kwargs) return wrapper class RateLimitedClient: def __init__(self, base_url, api_key, rate_limit=10): self.client = APIClient(base_url, api_key) self.limiter = RateLimiter(rate_limit) @property def get(self): return self.limiter(self.client.get) @property def post(self): return self.limiter(self.client.post) ``` ### Workflow 4: Pagination Handling ```python class PaginatedAPIClient(APIClient): def get_all_pages(self, endpoint, params=None): """Fetch all pages of results""" results = [] page = 1 params = params or {} while True: params['page'] = page response = self.get(endpoint, params=params) # Adjust based on API response structure items = response.get('items', []) results.extend(items) # Check if more pages exist if not response.get('has_more', False): break page += 1 return results def get_all_cursor(self, endpoint, params=None): """Fetch all results using cursor-based pagination""" results = [] cursor = None params = params or {} while True: if cursor: params['cursor'] = cursor response = self.get(endpoint, params=params) items = response.get('data', []) results.extend(items) cursor = response.get('next_cursor') if not cursor: break return results ``` ## Common Patterns ### Request Caching ```python from functools import lru_cache import hashlib import json class CachedAPIClient(APIClient): def __init__(self, base_url, api_key, cache_ttl=300): super().__init__(base_url, api_key) self.cache = {} self.cache_ttl = cache_ttl def _cache_key(self, method, endpoint, params): key_data = f"{method}:{endpoint}:{json.dumps(params, sort_keys=True)}" return hashlib.md5(key_data.encode()).hexdigest() def get_cached(self, endpoint, params=None): cache_key = self._cache_key("GET", endpoint, params or {}) if cache_key in self.cache: cached_data, cached_time = self.cache[cache_key] if time.time() - cached_time < self.cache_ttl: return cached_data data = self.get(endpoint, params=params) self.cache[cache_key] = (data, time.time()) return data ``` ### Webhook Signature Verification ```python import hmac import hashlib class WebhookValidator: def __init__(self, secret): self.secret = secret.encode() def verify_signature(self, payload, signature_header): """Verify webhook signature""" expected_signature = hmac.new( self.secret, payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected_signature, signature_header) ``` ## Testing API Integrations ### Using responses Library ```python import responses import requests @responses.activate def test_api_get(): # Mock the API response responses.add( responses.GET, 'https://api.example.com/users/123', json={'id': 123, 'name': 'Alice'}, status=200 ) client = APIClient('https://api.example.com', 'test-key') user = client.get('/users/123') assert user['name'] == 'Alice' @responses.activate def test_api_error_handling(): responses.add( responses.GET, 'https://api.example.com/users/999', json={'error': 'Not found'}, status=404 ) client = RobustAPIClient('https://api.example.com', 'test-key') with pytest.raises(NotFoundError): client.request('GET', '/users/999') ``` ## Common Pitfalls ### Issue: Leaking API Keys **Solution:** Never hardcode keys. Use environment variables or secret management: ```python import os api_key = os.environ.get('API_KEY') if not api_key: raise ValueError("API_KEY environment variable not set") ``` ### Issue: Not Handling Rate Limits **Solution:** Implement exponential backoff and respect rate limit headers: ```python def handle_rate_limit(response): if response.status_code == 429: retry_after = int(response.headers.get('Retry-After', 60)) time.sleep(retry_after) # Retry request ``` ### Issue: Timeout Issues **Solution:** Always set timeouts: ```python response = self.session.get(url, timeout=(3.0, 10.0)) # (connect, read) ``` ``` --- ## Example 3: Documentation Skill ### SKILL.md ```markdown --- name: Technical Documentation Writer description: Create clear, comprehensive technical documentation including API docs, README files, user guides, and code comments. Use when documenting code, APIs, or writing user-facing technical content. --- ## When to Use This Skill Use this skill when: - Writing README.md files for repositories - Documenting APIs (REST, GraphQL, SDKs) - Creating user guides and tutorials - Writing inline code documentation - Building developer onboarding materials Do NOT use this skill for: - Marketing copy or sales content - Academic papers or research documentation - Legal or compliance documentation ## Core Principles 1. **Write for your audience**: Junior developers need more context than senior engineers 2. **Show, don't just tell**: Include code examples for every concept 3. **Start with "why"**: Explain the purpose before the implementation 4. **Maintain consistency**: Use the same terminology throughout 5. **Keep it current**: Documentation that's out of date is worse than no documentation ## README.md Template ```markdown # Project Name Brief (1-2 sentence) description of what this project does. ## Features - Key feature 1 - Key feature 2 - Key feature 3 ## Installation \```bash npm install project-name \``` ## Quick Start \```javascript const Project = require('project-name'); const instance = new Project({ apiKey: 'your-api-key' }); const result = await instance.doSomething(); console.log(result); \``` ## Documentation Full documentation available at [link] ## Configuration | Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | required | Your API key | | timeout | number | 5000 | Request timeout in ms | ## Examples ### Example 1: Basic Usage [Code example with explanation] ### Example 2: Advanced Pattern [Code example with explanation] ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) ## License [License type] - see [LICENSE](LICENSE) ``` ## API Documentation Template ```markdown ## endpoint_name Brief description of what this endpoint does. ### HTTP Request \``` POST /api/v1/resource \``` ### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | name | string | Yes | Resource name | | type | string | No | Resource type (default: "standard") | | metadata | object | No | Additional metadata | ### Request Example \```json { "name": "example-resource", "type": "premium", "metadata": { "created_by": "user123" } } \``` ### Response \```json { "id": "res_abc123", "name": "example-resource", "type": "premium", "status": "active", "created_at": "2024-01-15T10:30:00Z" } \``` ### Errors | Status Code | Error Code | Description | |-------------|------------|-------------| | 400 | invalid_name | Name contains invalid characters | | 401 | unauthorized | Invalid or missing API key | | 409 | duplicate | Resource with this name already exists | ### Example Usage \```python import requests response = requests.post( 'https://api.example.com/api/v1/resource', headers={'Authorization': 'Bearer YOUR_API_KEY'}, json={ 'name': 'example-resource', 'type': 'premium' } ) resource = response.json() print(f"Created resource: {resource['id']}") \``` ``` ## Code Comment Guidelines ### Function Documentation **Python (docstring):** ```python def calculate_discount(price: float, discount_percent: float, min_price: float = 0) -> float: """ Calculate discounted price with minimum price floor. Args: price: Original price before discount discount_percent: Discount percentage (0-100) min_price: Minimum price floor (default: 0) Returns: Final price after applying discount, never below min_price Raises: ValueError: If discount_percent is not between 0 and 100 ValueError: If price or min_price is negative Examples: >>> calculate_discount(100, 20) 80.0 >>> calculate_discount(100, 20, min_price=85) 85.0 """ if not 0 <= discount_percent <= 100: raise ValueError("Discount percent must be between 0 and 100") if price < 0 or min_price < 0: raise ValueError("Prices cannot be negative") discounted = price * (1 - discount_percent / 100) return max(discounted, min_price) ``` **JavaScript (JSDoc):** ```javascript /** * Fetch user data from the API with caching * * @param {string} userId - The unique user identifier * @param {Object} options - Configuration options * @param {boolean} [options.skipCache=false] - Whether to bypass cache * @param {number} [options.timeout=5000] - Request timeout in ms * @returns {Promise} The user object * @throws {NotFoundError} If user doesn't exist * @throws {APIError} If the API request fails * * @example * const user = await fetchUser('user123'); * console.log(user.name); * * @example * // Skip cache for fresh data * const user = await fetchUser('user123', { skipCache: true }); */ async function fetchUser(userId, options = {}) { // Implementation } ``` ### Inline Comments **Good inline comments explain "why", not "what":** ```python # Good: Explains reasoning # Use a Set for O(1) lookup time since we'll be checking membership frequently seen_ids = set() # Bad: Just repeats what the code says # Create a set called seen_ids seen_ids = set() ``` ```python # Good: Explains non-obvious behavior # Delay between requests to avoid hitting rate limit (10 req/sec) time.sleep(0.1) # Bad: States the obvious # Sleep for 0.1 seconds time.sleep(0.1) ``` ## Common Pitfalls ### Issue: Documentation Out of Sync with Code **Solution:** - Keep docs close to code (docstrings, inline comments) - Auto-generate API docs from code when possible - Include doc updates in pull request checklist - Set up CI checks for documentation completeness ### Issue: Too Much or Too Little Detail **Solution:** - README: High-level overview + quick start - API Docs: Complete reference for every parameter - Tutorials: Step-by-step with context - Code Comments: Why, not what ### Issue: Examples Don't Run **Solution:** - Test all code examples as part of CI - Use tools like doctest (Python) or jsdoc-to-markdown - Include a "examples" directory with runnable code - Version examples alongside code releases ```