smithery.ai

python-development

Modern Python coding standards, best practices, testing patterns, and implementation guidelines

First seen Mar 11, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version3.10+
LicenseMIT
Compatibilityopencode
Declared agents opencode
More metadata
audience
developers
language
python
version
3.10+

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 14,991 B
  • docs SUMMARY.md 121 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 6 installs

SKILL.md

Python Development Skill

Modern Python Standards (3.10+)

Type Hints and Annotations

from typing import Protocol, TypeVar, Generic
from collections.abc import Sequence, Mapping
from pathlib import Path

# Modern union syntax (3.10+)
def process_data(data: str | int | None) -> str:
    match data:
        case str() if data.strip():
            return f"String: {data}"
        case int() if data > 0:
            return f"Positive int: {data}"
        case int() if data <= 0:
            return f"Non-positive int: {data}"
        case None:
            return "No data"
        case _:
            return "Invalid data"

# Protocol for structural typing
class Drawable(Protocol):
    def draw(self) -> None: ...
    def area(self) -> float: ...

def render_shape(shape: Drawable) -> None:
    print(f"Rendering shape with area: {shape.area()}")
    shape.draw()

# Generic types
T = TypeVar('T')

class Repository(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []

Pylance Integration for Development

# Pylance provides real-time type checking and IntelliSense
# Configure for optimal development experience

# Type-safe configuration patterns
from typing import TypedDict, Literal

class DatabaseConfig(TypedDict):
    host: str
    port: int
    database: str
    ssl_mode: Literal["disable", "require", "verify-full"]

def connect_database(config: DatabaseConfig) -> None:
    # Pylance ensures all required fields are present
    # and validates literal types
    pass

# Pylance catches type errors at development time
def process_user_data(user_id: int) -> dict[str, str]:
    # Pylance will warn about potential None returns
    user = get_user(user_id)  # type: User | None
    
    if user is None:
        raise ValueError("User not found")
    
    # Now Pylance knows user is not None
    return {
        "name": user.name,
        "email": user.email,
        "status": user.status
    }

# Advanced type narrowing with Pylance
def handle_response(response: dict[str, any]) -> str:
    if "error" in response:
        # Pylance understands type narrowing
        error_data = response["error"]
        if isinstance(error_data, dict) and "message" in error_data:
            return f"Error: {error_data['message']}"
        return "Unknown error occurred"
    
    if "data" in response:
        return str(response["data"])
    
    return "No data in response"

Development Workflow with Static Analysis

# Development setup for optimal type checking
# In pyproject.toml:
[tool.pylsp-mypy]
enabled = true
live_mode = true
strict = true

[tool.ruff]
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # Pyflakes
    "I",    # isort
    "N",    # pep8-naming
    "UP",   # pyupgrade
    "B",    # flake8-bugbear
    "A",    # flake8-builtins
    "C4",   # flake8-comprehensions
    "T20",  # flake8-print
]

# Pre-commit hooks for code quality
# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: pylance-check
        name: Pylance type check
        entry: pylance
        language: system
        args: ["--check"]
        files: \.py$
      
      - id: mypy
        name: MyPy type check
        entry: mypy
        language: system
        args: ["--strict"]
        files: \.py$
      
      - id: ruff
        name: Ruff linter
        entry: ruff
        language: system
        args: ["check", "--fix"]
        files: \.py$

def add(self, item: T) -> None: self._items.append(item)

def getall(self) -> list[T]: return self.items.copy()


### Modern Python Idioms

**Dataclasses and Pydantic**

from dataclasses import dataclass, field from typing import Optional from datetime import datetime

@dataclass class User: name: str email: str createdat: datetime = field(defaultfactory=datetime.now) active: bool = True tags: list[str] = field(default_factory=list)

def __post_init__(self): if "@" not in self.email: raise ValueError("Invalid email format")

Pydantic for validation (external data)

from pydantic import BaseModel, EmailStr, Field

class UserModel(BaseModel): name: str = Field(..., minlength=1, maxlength=100) email: EmailStr age: int = Field(ge=0, le=150)

class Config: validate_assignment = True


**Context Managers**

from contextlib import contextmanager import sqlite3

@contextmanager def databasetransaction(dbpath: str): conn = sqlite3.connect(db_path) try: yield conn conn.commit() except Exception: conn.rollback() raise finally: conn.close()

Usage

with database_transaction("app.db") as conn: conn.execute("INSERT INTO users (name) VALUES (?)", ("Alice",))


**Pathlib Usage**

from pathlib import Path

def processconfigfiles(configdir: str | Path) -> dict[str, str]: configpath = Path(config_dir)

if not configpath.exists(): raise FileNotFoundError(f"Config directory not found: {configpath}")

configs = {} for configfile in configpath.glob("*.yaml"): with configfile.open() as f: configs[configfile.stem] = f.read()

return configs


## Error Handling Patterns

### Custom Exceptions

class AppException(Exception): """Base exception for application-specific errors.""" pass

class ValidationError(AppException): """Raised when data validation fails.""" def init(self, field: str, value: any, message: str): self.field = field self.value = value super().init(f"Validation failed for {field}: {message}")

class DatabaseError(AppException): """Raised when database operations fail.""" pass

def validateuserage(age: int) -> None: if age < 0 or age > 150: raise ValidationError("age", age, "must be between 0 and 150")


### Error Handling Best Practices

import logging from typing import Optional

logger = logging.getLogger(name)

def safe_divide(a: float, b: float) -> Optional[float]: """Safely divide two numbers, returning None if division by zero.""" try: return a / b except ZeroDivisionError: logger.warning(f"Division by zero attempted: {a} / {b}") return None

def processuserdata(data: dict) -> dict: """Process user data with comprehensive error handling.""" try: # Validate required fields if not (name := data.get("name", "").strip()): raise ValidationError("name", data.get("name"), "is required")

if not (email := data.get("email", "").strip()): raise ValidationError("email", data.get("email"), "is required")

# Process data return { "name": name.title(), "email": email.lower(), "created_at": datetime.now().isoformat() }

except ValidationError: logger.error(f"User data validation failed: {data}") raise except Exception as e: logger.exception("Unexpected error processing user data") raise AppException(f"Failed to process user data: {e}") from e


## Testing Patterns

### Pytest Best Practices

import pytest from unittest.mock import Mock, patch from pathlib import Path

Fixtures

@pytest.fixture def user_data(): return { "name": "Alice Smith", "email": "[email protected]", "age": 30 }

@pytest.fixture def tempconfigdir(tmppath): """Create a temporary config directory with test files.""" configdir = tmppath / "config" configdir.mkdir()

(configdir / "app.yaml").writetext("debug: true\nport: 8000\n") (configdir / "db.yaml").writetext("host: localhost\nport: 5432\n")

return config_dir

Parametrized tests

@pytest.mark.parametrize("inputage,expected", [ (25, True), (0, True), (150, True), (-1, False), (151, False), ]) def testagevalidation(inputage, expected): if expected: validateuserage(inputage) # Should not raise else: with pytest.raises(ValidationError): validateuserage(inputage)

Mocking

def testdatabaseoperation(): with patch('app.database.connect') as mockconnect: mockconn = Mock() mockconnect.returnvalue = mock_conn

result = somedatabaseoperation()

mockconnect.assertcalledonce() mockconn.execute.assertcalledwith("SELECT * FROM users")

Async testing

@pytest.mark.asyncio async def testasyncapicall(): with patch('httpx.AsyncClient.get') as mockget: mockresponse = Mock() mockresponse.statuscode = 200 mockresponse.json.returnvalue = {"success": True} mockget.returnvalue = mockresponse

result = await fetchuserdata("123")

assert result["success"] is True mockget.assertcalled_once()


### Test Organization

tests/conftest.py - Shared fixtures

import pytest from app import create_app

@pytest.fixture def app(): return create_app(testing=True)

@pytest.fixture def client(app): return app.test_client()

tests/test_models.py - Model tests

class TestUser: def testusercreation(self, userdata): user = User(**userdata) assert user.name == "Alice Smith" assert user.email == "[email protected]"

def testinvalidemailraiseserror(self): with pytest.raises(ValidationError): User(name="Test", email="invalid-email")

tests/test_services.py - Service tests

class TestUserService: @pytest.fixture(autouse=True) def setup(self): self.service = UserService()

def testcreateusersuccess(self, userdata): user = self.service.createuser(userdata) assert user.id is not None assert user.name == user_data["name"]


## Performance and Optimization

### Profiling and Timing

import time import functools from typing import Callable, Any

def timer(func: Callable) -> Callable: """Decorator to time function execution.""" @functools.wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: start = time.perfcounter() result = func(*args, **kwargs) end = time.perfcounter() print(f"{func.name} took {end - start:.4f} seconds") return result return wrapper

@timer def slow_operation(n: int) -> list[int]: return [i**2 for i in range(n)]

Memory profiling with tracemalloc

import tracemalloc

def profilememory(func: Callable) -> Callable: @functools.wraps(func) def wrapper(*args, **kwargs): tracemalloc.start() result = func(*args, **kwargs) current, peak = tracemalloc.gettraced_memory() tracemalloc.stop() print(f"{func.name} - Current: {current / 1024 / 1024:.2f}MB, Peak: {peak / 1024 / 1024:.2f}MB") return result return wrapper


### Async Best Practices

import asyncio import aiohttp from typing import List

async def fetch_url(session: aiohttp.ClientSession, url: str) -> dict: """Fetch a single URL.""" async with session.get(url) as response: return await response.json()

async def fetchmultipleurls(urls: List[str]) -> List[dict]: """Fetch multiple URLs concurrently.""" async with aiohttp.ClientSession() as session: tasks = [fetchurl(session, url) for url in urls] return await asyncio.gather(*tasks, returnexceptions=True)

Semaphore for rate limiting

async def fetchwithlimit(urls: List[str], maxconcurrent: int = 10) -> List[dict]: """Fetch URLs with concurrency limit.""" semaphore = asyncio.Semaphore(maxconcurrent)

async def fetchlimited(url: str) -> dict: async with semaphore: async with aiohttp.ClientSession() as session: return await fetchurl(session, url)

tasks = [fetchlimited(url) for url in urls] return await asyncio.gather(*tasks, returnexceptions=True)


## Configuration and Environment Management

### Configuration Pattern

from dataclasses import dataclass from pathlib import Path import os from typing import Optional

@dataclass class DatabaseConfig: host: str = "localhost" port: int = 5432 username: str = "user" password: str = "" database: str = "app_db"

@property def url(self) -> str: return f"postgresql://{self.username}:{self.password}@{self.host}:{self.port}/{self.database}"

@dataclass class AppConfig: debug: bool = False secret_key: str = "" database: DatabaseConfig = DatabaseConfig()

@classmethod def fromenv(cls) -> "AppConfig": return cls( debug=os.getenv("DEBUG", "false").lower() == "true", secretkey=os.getenv("SECRETKEY", "dev-key"), database=DatabaseConfig( host=os.getenv("DBHOST", "localhost"), port=int(os.getenv("DBPORT", "5432")), username=os.getenv("DBUSER", "user"), password=os.getenv("DBPASSWORD", ""), database=os.getenv("DBNAME", "app_db"), ) )

Usage

config = AppConfig.from_env()


### Logging Configuration

import logging.config import sys

LOGGINGCONFIG = { "version": 1, "disableexisting_loggers": False, "formatters": { "standard": { "format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s" }, "detailed": { "format": "%(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s" } }, "handlers": { "console": { "class": "logging.StreamHandler", "level": "INFO", "formatter": "standard", "stream": sys.stdout }, "file": { "class": "logging.FileHandler", "level": "DEBUG", "formatter": "detailed", "filename": "app.log" } }, "loggers": { "": { # Root logger "level": "INFO", "handlers": ["console", "file"] }, "app": { "level": "DEBUG", "handlers": ["console", "file"], "propagate": False } } }

def setuplogging(): logging.config.dictConfig(LOGGINGCONFIG)

Usage in modules

logger = logging.getLogger(name) logger.info("Application started")


These patterns provide a solid foundation for writing maintainable, tested, and performant Python code following modern best practices.