internal/skills/content/python-guide/SKILL.md
Python guardrails, patterns, and best practices for AI-assisted development. Use when working with Python files (.py), requirements.txt, pyproject.toml, or when the user mentions Python. Provides type hint conventions, virtual environment standards, testing with pytest, and async patterns.
npx skillsauth add ar4mirez/samuel python-guideInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Applies to: Python 3.11+, APIs, CLIs, Data Pipelines, Automation
* imports, no mutable default arguments, no implicit type coercionsvenv, uv, or poetrymatch statements, ExceptionGroup, tomllib)requires-python = ">=3.11" in pyproject.tomlfrom __future__ import annotations for forward references in 3.11distutils, imp, legacy typing aliases)ruff check and ruff format before every commitisort/ruff)snake_case for functions/variables, PascalCase for classes, UPPER_SNAKE for constantsexcept: — always catch specific exceptionsdef f(items=None): not def f(items=[]):).format() or % formattingpathlib.Path instead of os.path for all file operationscollections.abc types: Sequence, Mapping, Iterable (not List, Dict)X | None union syntax (not Optional[X])TypeAlias for complex types: UserMap: TypeAlias = dict[str, User]Protocol for structural subtyping (duck typing with safety)@overload for functions returning different types based on inputmypy --strict in CI (no type: ignore without explanation)from collections.abc import Sequence
def find_users(
ids: Sequence[str],
*,
active_only: bool = True,
) -> list[User]:
"""Fetch users by ID list, optionally filtering inactive."""
...
except: or except Exception: without re-raisingraise ... from err to preserve exception chainscontextlib.suppress() instead of empty except blockswith statements or contextlib.closingpyproject.toml (not setup.py or bare requirements.txt)uv.lock, poetry.lock, pip-compile output)requirements.txt only as a generated artifact, never hand-edited[project.optional-dependencies] for dev, test, docspip-audit or safety before adding new packagestomllib, pathlib, dataclasses, enum, loggingmyproject/
├── src/
│ └── myproject/ # Importable package (src layout)
│ ├── __init__.py
│ ├── py.typed # PEP 561 marker for type stubs
│ ├── domain/ # Business logic, entities
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── exceptions.py
│ ├── service/ # Application services
│ │ └── __init__.py
│ ├── repository/ # Data access layer
│ │ └── __init__.py
│ └── api/ # HTTP/CLI interface
│ └── __init__.py
├── tests/
│ ├── conftest.py # Shared fixtures
│ ├── unit/
│ └── integration/
├── pyproject.toml # Single source of truth for config
├── uv.lock # Or poetry.lock
└── README.md
src/myproject/) to prevent accidental local importsconftest.py at test root for shared fixtures; nest for scopepy.typed marker for downstream type checking__init__.py in tests/ (pytest discovers without it)class AppError(Exception):
"""Base exception for the application."""
def __init__(self, message: str, *, code: str = "UNKNOWN") -> None:
super().__init__(message)
self.code = code
class NotFoundError(AppError):
"""Raised when a requested resource does not exist."""
def __init__(self, resource: str, identifier: str) -> None:
super().__init__(
f"{resource} with id '{identifier}' not found",
code="NOT_FOUND",
)
self.resource = resource
self.identifier = identifier
class ValidationError(AppError):
"""Raised when input data fails validation."""
def __init__(self, field: str, reason: str) -> None:
super().__init__(
f"Validation failed for '{field}': {reason}",
code="VALIDATION_ERROR",
)
from contextlib import contextmanager
from collections.abc import Generator
@contextmanager
def managed_connection(url: str) -> Generator[Connection, None, None]:
conn = Connection(url)
try:
conn.open()
yield conn
except ConnectionError as err:
raise AppError("Database unavailable") from err
finally:
conn.close()
def get_user(user_id: str) -> User:
try:
row = db.fetch_one("SELECT * FROM users WHERE id = %s", (user_id,))
except DatabaseError as err:
raise AppError(f"Failed to fetch user {user_id}") from err
if row is None:
raise NotFoundError("User", user_id)
return User.from_row(row)
test_*.py (same name as module: models.py -> test_models.py)test_<unit>_<scenario>_<expected> (e.g., test_get_user_not_found_raises)conftest.py for fixtures shared across a directory@pytest.mark.slow and exclude from default runsunittest.TestCase — use plain functions with pytest assertionstmp_path fixture for file operations (auto-cleanup)import pytest
from myproject.domain.models import User
@pytest.fixture
def sample_user() -> User:
return User(id="u-123", name="Ada Lovelace", email="[email protected]")
@pytest.mark.parametrize(
("email", "is_valid"),
[
("[email protected]", True),
("[email protected]", False),
("", False),
("user@domain", False),
],
)
def test_validate_email(email: str, is_valid: bool) -> None:
assert validate_email(email) == is_valid
def test_get_user_returns_user(sample_user: User) -> None:
repo = InMemoryUserRepo(users=[sample_user])
result = repo.get("u-123")
assert result == sample_user
def test_get_user_not_found_raises() -> None:
repo = InMemoryUserRepo(users=[])
with pytest.raises(NotFoundError, match="User.*not found"):
repo.get("nonexistent")
from unittest.mock import AsyncMock, patch
async def test_send_notification_retries_on_failure() -> None:
mock_client = AsyncMock()
mock_client.post.side_effect = [ConnectionError, None]
with patch("myproject.service.notify.http_client", mock_client):
await send_notification(user_id="u-123", message="hello")
assert mock_client.post.call_count == 2
[project]
name = "myproject"
requires-python = ">=3.11"
[project.optional-dependencies]
dev = ["ruff", "mypy", "pytest", "pytest-cov", "pytest-asyncio"]
[tool.ruff]
target-version = "py311"
line-length = 88
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"B", # flake8-bugbear
"S", # flake8-bandit (security)
"A", # flake8-builtins
"C4", # flake8-comprehensions
"SIM", # flake8-simplify
"RUF", # ruff-specific rules
]
[tool.mypy]
strict = true
warn_return_any = true
disallow_untyped_defs = true
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"]
asyncio_mode = "auto"
[tool.coverage.run]
source = ["src/myproject"]
branch = true
[tool.coverage.report]
fail_under = 60
show_missing = true
exclude_lines = ["if TYPE_CHECKING:", "pragma: no cover"]
ruff check . # Lint (replaces flake8, isort, pyupgrade)
ruff format . # Format (replaces black)
mypy . # Type check (strict mode)
pytest # Run all tests
pytest --cov=src -q # Coverage summary
pytest -m "not slow" # Skip slow tests
pip-audit # Check dependencies for vulnerabilities
python -m build # Build sdist + wheel
For detailed patterns and examples, see:
development
Zig language guardrails, patterns, and best practices for AI-assisted development. Use when working with Zig files (.zig), build.zig, or when the user mentions Zig. Provides comptime patterns, allocator conventions, C interop guidelines, and testing standards specific to this project's coding standards.
tools
WordPress framework guardrails, patterns, and best practices for AI-assisted development. Use when working with WordPress projects, or when the user mentions WordPress. Provides theme development, plugin architecture, REST API, blocks, and security guidelines.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs. Use when testing web apps, automating browser interactions, or debugging frontend issues.
tools
Suite of tools for creating elaborate, multi-component web applications using modern frontend technologies (React, Tailwind CSS, shadcn/ui). Use for complex projects requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX pages.