Dignified Python - Python 3.13+ Coding Standards
Write explicit, predictable code that fails fast at proper boundaries.
Quick Reference - Check Before Coding
| If you're about to write... | Check this rule |
|---|---|
try: or except: | → Exception Handling - Default: let exceptions bubble |
from __future__ import annotations | → FORBIDDEN - Python 3.13+ doesn't need it |
List[...], Dict[...], Union[...] | → Use list[...], dict[...], X | Y |
dict[key] without checking | → Use if key in dict: or .get() |
path.resolve() or path.is_relative_to() | → Check path.exists() first |
typing.Protocol | → Use abc.ABC instead |
from .module import | → Use absolute imports only |
__all__ = ["..."] in __init__.py | → See references/core-standards.md#code-in-initpy-and-all-exports |
print(...) in CLI code | → Use click.echo() |
subprocess.run(...) | → Add check=True |
@property with I/O or expensive computation | → See references/core-standards.md#performance-expectations |
| Function with many optional parameters | → See references/code-smells-dagster.md |
repr() for sorting or hashing | → See references/code-smells-dagster.md |
| Context object passed everywhere | → See references/code-smells-dagster.md |
| Function with 10+ local variables | → See references/code-smells-dagster.md |
| Class with 50+ methods | → See references/code-smells-dagster.md |
CRITICAL RULES (Top 6)
1. Exception Handling - NEVER for Control Flow 🔴
ALWAYS use LBYL (Look Before You Leap), NEVER EAFP
# ✅ CORRECT: Check before acting
if key in mapping:
value = mapping[key]
else:
handle_missing_key()
# ❌ WRONG: Using exceptions for control flow
try:
value = mapping[key]
except KeyError:
handle_missing_key()
Details: See references/core-standards.md#exception-handling for complete patterns
2. Type Annotations - Python 3.13+ Syntax Only 🔴
FORBIDDEN: from __future__ import annotations
# ✅ CORRECT: Modern Python 3.13+ syntax def process(items: list[str]) -> dict[str, int]: ... def find_user(id: int) -> User | None: ... # ❌ WRONG: Legacy syntax from typing import List, Dict, Optional def process(items: List[str]) -> Dict[str, int]: ...
Details: See references/core-standards.md#type-annotations for all patterns
3. Path Operations - Check Exists First 🔴
# ✅ CORRECT: Check exists first
if path.exists():
resolved = path.resolve()
# ❌ WRONG: Using exceptions
try:
resolved = path.resolve()
except OSError:
pass
Details: See references/core-standards.md#path-operations
4. Dependency Injection - ABC Not Protocol 🔴
# ✅ CORRECT: Use ABC
from abc import ABC, abstractmethod
class MyOps(ABC):
@abstractmethod
def operation(self) -> None: ...
# ❌ WRONG: Using Protocol
from typing import Protocol
Details: See references/core-standards.md#dependency-injection
5. Imports - Module-Level and Absolute 🔴
ALL imports must be at module level unless preventing circular imports
# ✅ CORRECT: Module-level, absolute imports
from erk.config import load_config
from pathlib import Path
import click
# ❌ WRONG: Inline imports (unless for circular import prevention)
def my_function():
from erk.config import load_config # WRONG unless circular import
return load_config()
# ❌ WRONG: Relative imports
from .config import load_config
Exception: Inline imports are ONLY acceptable when preventing circular imports. Always document why:
def create_context():
# Inline import to avoid circular dependency with tests
from tests.fakes.gitops import FakeGitOps
return FakeGitOps()
Details: See references/core-standards.md#imports
6. No Silent Fallback Behavior 🔴
# ❌ WRONG: Silent fallback
try:
result = primary_method()
except:
result = fallback_method() # Untested, brittle
# ✅ CORRECT: Let error bubble up
result = primary_method()
Details: See references/core-standards.md#anti-patterns
When to Load References
Load references/core-standards.md when:
- •Writing exception handling code (LBYL patterns)
- •Working with type annotations (Python 3.13+ syntax)
- •Implementing path operations (exists() checks)
- •Creating ABC interfaces (dependency injection)
- •Organizing imports (absolute imports, module-level)
- •Working with CLI code (Click patterns)
- •Using dataclasses and immutability
- •Avoiding anti-patterns (silent fallback, exception swallowing)
- •Implementing
@propertyor__len__(performance expectations)
Load references/code-smells-dagster.md when:
- •Designing function APIs (default parameters, keyword arguments)
- •Managing parameter complexity (parameter anxiety, invalid combinations)
- •Refactoring large functions/classes (god classes, local variables)
- •Working with context managers (assignment patterns)
- •Using
repr()programmatically (string representation abuse) - •Passing context objects (context coupling)
- •Dealing with error boundaries (early validation)
Load references/patterns-reference.md when:
- •Developing CLI commands with Click
- •Working with file I/O and pathlib
- •Implementing dataclasses and frozen structures
- •Managing subprocess operations
- •Reducing code nesting (early returns, helper functions)
Progressive Disclosure Guide
This skill uses a three-level loading system:
- •This file (SKILL.md): Core rules and navigation (~350 lines)
- •Reference files: Detailed patterns and examples (loaded as needed)
- •Quick lookup: Use the tables above to find what you need
Claude loads reference files only when needed based on the current task. The reference files contain:
- •
core-standards.md: Foundational Python patterns from this skill - •
code-smells-dagster.md: Production-tested anti-patterns from Dagster Labs - •
patterns-reference.md: Common implementation patterns and examples
Philosophy
Write dignified Python code that:
- •Fails fast at proper boundaries (not deep in the stack)
- •Makes invalid states unrepresentable (use the type system)
- •Expresses intent clearly (LBYL over EAFP)
- •Minimizes cognitive load (explicit over implicit)
- •Enables confident refactoring (test what you build)
Default stances:
- •Let exceptions bubble up (handle at boundaries only)
- •Break APIs and migrate immediately (no unnecessary backwards compatibility)
- •Check conditions proactively (LBYL)
- •Use modern Python 3.13+ syntax
Quick Decision Tree
About to write Python code?
- •
Using
try/except?- •Can you use LBYL instead? → Do that
- •Is this an error boundary? → OK to handle
- •Otherwise → Let it bubble
- •
Using type hints?
- •Use
list[str],str | None, notList,Optional - •NO
from __future__ import annotations
- •Use
- •
Working with paths?
- •Check
.exists()before.resolve() - •Use
pathlib.Path, notos.path
- •Check
- •
Writing CLI code?
- •Use
click.echo(), notprint() - •Exit with
raise SystemExit(1)
- •Use
- •
Too many parameters?
- •See
references/code-smells-dagster.md#parameter-anxiety
- •See
- •
Class getting large?
- •See
references/code-smells-dagster.md#god-classes
- •See
Checklist Before Writing Code
Before writing try/except:
- • Can I check the condition proactively? (LBYL)
- • Is this at an error boundary? (CLI/API level)
- • Am I adding meaningful context or just hiding the error?
Before using type hints:
- • Am I using Python 3.13+ syntax? (
list,dict,|) - • Have I removed all
typingimports except essentials?
Before path operations:
- • Did I check
.exists()before.resolve()? - • Am I using
pathlib.Path? - • Did I specify
encoding="utf-8"?
Before adding backwards compatibility:
- • Did the user explicitly request it?
- • Is this a public API?
- • Default: Break and migrate immediately
Common Patterns Summary
| Scenario | Preferred Approach | Avoid |
|---|---|---|
| Dictionary access | if key in dict: or .get(key, default) | try: dict[key] except KeyError: |
| File existence | if path.exists(): | try: open(path) except FileNotFoundError: |
| Type checking | if isinstance(obj, Type): | try: obj.method() except AttributeError: |
| Value validation | if is_valid(value): | try: process(value) except ValueError: |
| Path resolution | if path.exists(): path.resolve() | try: path.resolve() except OSError: |
References
- •Core Standards:
references/core-standards.md- Detailed LBYL patterns, type annotations, imports - •Code Smells:
references/code-smells-dagster.md- Production-tested anti-patterns - •Pattern Reference:
references/patterns-reference.md- CLI, file I/O, dataclasses - •Python 3.13 docs: https://docs.python.org/3.13/