Skip to content

Instantly share code, notes, and snippets.

@bofm
bofm / Terragrunt-not-needed.md
Created December 26, 2025 18:58
Terragrunt not needed.md

The Terragrunt Guide Creates the Problem It Solves

Gruntwork’s “Terralith to Terragrunt” guide is well-written and comprehensive. It’s also a masterclass in manufacturing complexity to sell a solution.

I walked through the guide step by step. Here’s where it goes wrong — and what to do instead.

Step 1: A Reasonable Start

You begin with flat resources in a live/ directory. S3 bucket, DynamoDB table, IAM role, Lambda function. All in one state file. Simple.

@bofm
bofm / oidc-debugger.py
Created July 25, 2025 06:16
OIDC debugger script
#!/usr/bin/env python3
# /// script
# dependencies = [
# "flask",
# "requests",
# "pyjwt[crypto]",
# "cryptography"
# ]
# ///
@bofm
bofm / py_guidelines.md
Created June 23, 2024 11:34
Python Project Development Guidelines

Project Guidelines

Favor Class Composition Over Inheritance

  • Reduced Coupling: Using composition over inheritance reduces coupling between classes, making the codebase easier to maintain and understand.
  • Explicit Dependencies: It's clear what dependencies are required by a class.
  • Increased Flexibility: Composition allows dynamic behavior swapping, unlike inheritance which is static.
  • Ease of Testing: Testing composed objects is often simpler because you can isolate components.
# Good: Using Composition
@bofm
bofm / calculate_new_coverage.py
Last active September 11, 2023 07:52
Calculate test coverage for the new code only. Usable in pull/merge requests.
"""
Calculates test coverage for the new code only, that is for the added and
changed lines of code.
Usage:
pytest --cov --cov-report=xml
git diff master..HEAD |python calculate_new_coverage.py --coverage-report coverage.xml
"""
@bofm
bofm / argparse_call.py
Created July 6, 2023 08:56
Automatically parse args and call a function based on it's signature.
import inspect
from argparse import ArgumentParser
def argparse_call(fn):
sig = inspect.signature(fn)
p = ArgumentParser()
for param in sig.parameters.values():
kwargs = {
'type': param.annotation,
@bofm
bofm / pydantic_typed_dict.py
Last active January 13, 2021 21:00
python pydantic typed dict validation
from functools import wraps
from typing import TypedDict
from pydantic import BaseModel, validate_arguments
def replace_typed_dict_annotations(annotations):
new_annotations = {}
for k, T in annotations.items():
if type(T).__name__ == '_TypedDictMeta':
from typing import (
Any,
Dict,
NamedTuple,
)
import pytest
class Case(NamedTuple):
from dataclasses import dataclass
import pytest
from lib.util import paths_eq
from collections.abc import Mapping
_MISS = object()
@bofm
bofm / f.py
Last active June 28, 2020 11:37
f
from functools import partial
class F:
__slots__ = ('fns',)
def __init__(self, *fns):
self.fns = fns
def __call__(self, *args, **kwargs):
@bofm
bofm / compose.py
Last active June 12, 2020 22:23
Python compose picklable
class compose:
__slots__ = ('f', 'fs')
def __init__(self, *fs):
self.f, *self.fs = reversed(fs)
def __call__(self, *args, **kwargs):
result = self.f(*args, **kwargs)
for f in self.fs:
result = f(result)