Debugging Refactor Snippets
Copy-paste before/after pairs for defects covered in this section. Each snippet is a minimal, runnable pattern you can drop into a failing codebase and adapt.
Search across all documentation pages
Copy-paste before/after pairs for defects covered in this section. Each snippet is a minimal, runnable pattern you can drop into a failing codebase and adapt.
Start with the one-line or five-line fix (sentinel None, explicit encoding, math.isclose). Ship the smallest change with a test, then refactor structure if the pattern repeats.
# BEFORE
def add(item, items=[]):
items.append(item)
return items
# AFTER
def add(item, items=None):
if items is None:
items = []
items.append(item)
return items# BEFORE
from dataclasses import dataclass
@dataclass
class Cart:
lines: list[str] = []
# AFTER
from dataclasses import dataclass, field
@dataclass
class Cart:
lines: list[str] = field(default_factory=list)# BEFORE
# orders.py imports billing.py; billing.py imports orders.py
# AFTER
# types.py holds shared dataclasses
from dataclasses import dataclass
@dataclass(frozen=True)
class OrderId:
value: str# BEFORE
async def route():
import time
time.sleep(1)
# AFTER
import asyncio
async def route():
await asyncio.sleep(1)# BEFORE
async def fetch(url: str):
import urllib.request
return urllib.request.urlopen(url).read()
# AFTER
import httpx
async def fetch(client: httpx.AsyncClient, url: str):
return (await client.get(url)).content# BEFORE
total = 19.99 * 3
# AFTER
from decimal import Decimal, ROUND_HALF_UP
total = (Decimal("19.99") * 3).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)# BEFORE
if result == expected_float:
# AFTER
import math
if math.isclose(result, expected_float, rel_tol=1e-9):# BEFORE
text = open(path).read()
# AFTER
from pathlib import Path
text = Path(path).read_text(encoding="utf-8")# BEFORE
payload = "prefix" + b"bytes"
# AFTER
payload = "prefix".encode("utf-8") + b"bytes"# BEFORE
merged = left.merge(right, on="id")
# AFTER
merged = left.merge(right, on="id", validate="one_to_one")
assert len(merged) == len(left)# BEFORE
total = df["amount"].sum()
# AFTER
total = df.dropna(subset=["amount"])["amount"].sum()# BEFORE
pip install -r requirements.txt
# AFTER
uv sync --frozen
uv run pytestProduction-ready pattern combining guardrails for a billing microservice hot path:
from __future__ import annotations
import asyncio
import logging
from dataclasses import dataclass, field
from decimal import Decimal, ROUND_HALF_UP
from typing import Protocol
import httpx
log = logging.getLogger(__name__)
@dataclass(frozen=True)
class Money:
cents: int
@staticmethod
def from_decimal(amount: str, qty: int) -> "Money":
total = (Decimal(amount) * qty).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
return Money(int(total * 100))
class TaxClient(Protocol):
async def rate_for(self, region: str) -> Decimal: ...
class HttpxTaxClient:
def __init__(self, client: httpx.AsyncClient) -> None:
self._client = client
async def rate_for(self, region: str) -> Decimal:
resp = await self._client.get(f"/tax/{region}", timeout=5.0)
resp.raise_for_status()
return Decimal(str(resp.json()["rate"]))
@dataclass
class QuoteService:
tax_client: TaxClient
_cache: dict[str, Decimal] = field(default_factory=dict)
async def quote(self, region: str, unit_price: str, qty: int) -> Money:
subtotal = Money.from_decimal(unit_price, qty)
rate = self._cache.get(region)
if rate is None:
rate = await self.tax_client.rate_for(region)
self._cache[region] = rate
tax = (Decimal(subtotal.cents) / 100 * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
return Money(subtotal.cents + int(tax * 100))
async def main() -> None:
async with httpx.AsyncClient(base_url="https://example.test") as client:
svc = QuoteService(HttpxTaxClient(client))
log.info("quote", extra={"amount": svc.quote("TX", "19.99", 2)})
if __name__ == "__main__":
asyncio.run(main())Key aspects:
httpx with timeout instead of blocking urllibdefault_factory=dict, not mutable defaultDecimal parsed from JSON string, not floatto_thread or async client to the actual IO call.Decimal(resp.json()["x"]) when x is float reintroduces error. Fix: stringify at API or use int cents._cache dict grows forever in snippet above. Fix: add LRU/TTL when regions are unbounded.No. One defect class per PR with tests. Combined refactors obscure which fix solved the issue.
Prefer fixing source modules and capturing patterns in internal docs or this reference. Avoid a growing snippets.py imported in prod.
ruff 0.9+ flags some mutable defaults and debug statements. Encoding and Decimal changes need human review.
Deploy behind metrics: error rate, p95 latency, memory RSS, and business reconciliation totals for data fixes.
Minimal examples are for illustration. Mutable-default before blocks mutate shared state if called repeatedly in one process.
After fixes, add types (list[str] | None, Decimal) so mypy/pyright prevent regressions.
Leaf types or protocols module, not permanent lazy imports. Lazy import variation is emergency only.
Int cents for fixed-scale currency in high throughput. Decimal when tax rules need arbitrary precision before quantize.
Negligible on moderate data; invaluable during development. Remove only after automated key uniqueness checks exist.
Yes. Apply encoding and Decimal patterns in views/services; keep ORM boundary mapping explicit.
uv sync --frozen plus python -c "import pkg; print(pkg.__file__)" before deeper debugging.
Use snippets after pdb/logging identified the defect class. Tools find; snippets fix structurally.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026