Claude Code for python-benedict: Dict with Keypath Support in Python — Claude Skills 360 Blog
Blog / AI / Claude Code for python-benedict: Dict with Keypath Support in Python
AI

Claude Code for python-benedict: Dict with Keypath Support in Python

Published: April 10, 2028
Read time: 5 min read
By: Claude Skills 360

python-benedict is a Python dict subclass with keypath access, multi-format I/O, and transformation utilities. pip install python-benedict. Import: from benedict import benedict. Create: b = benedict({"a": {"b": 1}}). Access: b["a.b"] → 1. b.get("a.b", default=0). Set: b["a.b"] = 2. Delete: del b["a.b"]. Custom separator: benedict(data, keypath_separator="/"). From JSON: b = benedict.from_json('{"key": 1}'). From YAML: benedict.from_yaml("key: value"). From TOML: benedict.from_toml(toml_str). From URL: benedict.from_url("https://api.example.com/data.json"). From base64: benedict.from_base64(encoded). From CSV: benedict.from_csv(csv_str). To JSON: b.to_json(indent=2). To YAML: b.to_yaml(). Merge: b.merge(other) — deep merge. Subset: b.subset(["a.b", "a.c"]). Rename: b.rename("old_key", "new_key"). Clean: b.clean() — remove None values. Filter: b.filter(keys=["a", "b"]). b.invert() — swap keys/values. b.flatten(separator="_"). b.unflatten(separator="_"). b.keypaths() — all keypaths. b.match("a.*") — wildcard search. Clone: b.clone(). Swap: b.swap("key1", "key2"). b.traverse(fn). Standardize: b.standardize() — lowercase+underscore keys. Claude Code generates benedict config handlers, API response parsers, and nested data transformation utilities.

CLAUDE.md for python-benedict

## python-benedict Stack
- Version: python-benedict >= 0.33 | pip install python-benedict
- Create: benedict(dict) | from_json/yaml/toml/url/base64/csv class methods
- Access: b["a.b.c"] keypath | b.get("a.b", default=val)
- Mutate: b["a.b"] = val | b.merge(other) | b.clean() | b.rename("k","v")
- Output: b.to_json() | b.to_yaml() | b.to_toml() | b.to_csv()
- Utils: b.subset(keys) | b.flatten("_") | b.unflatten("_") | b.keypaths()

python-benedict Dict Pipeline

# app/dict_utils.py — benedict keypath access, format I/O, merge, transform, config
from __future__ import annotations

import os
from pathlib import Path
from typing import Any, Callable

from benedict import benedict


# ─────────────────────────────────────────────────────────────────────────────
# 1. Creation helpers
# ─────────────────────────────────────────────────────────────────────────────

def from_dict(data: dict, separator: str = ".") -> benedict:
    """Wrap an existing dict as a benedict with the given keypath separator."""
    return benedict(data, keypath_separator=separator)


def from_json(json_str: str) -> benedict:
    """Parse a JSON string into a benedict."""
    return benedict.from_json(json_str)


def from_yaml(yaml_str: str) -> benedict:
    """Parse a YAML string into a benedict."""
    return benedict.from_yaml(yaml_str)


def from_toml(toml_str: str) -> benedict:
    """Parse a TOML string into a benedict."""
    return benedict.from_toml(toml_str)


def load_file(path: str | Path) -> benedict:
    """
    Load a config or data file by extension.
    Supports: .json, .yaml/.yml, .toml, .csv, .xml
    """
    p = Path(path)
    suffix = p.suffix.lower()
    text = p.read_text(encoding="utf-8")
    if suffix == ".json":
        return benedict.from_json(text)
    if suffix in (".yaml", ".yml"):
        return benedict.from_yaml(text)
    if suffix == ".toml":
        return benedict.from_toml(text)
    if suffix == ".xml":
        return benedict.from_xml(text)
    if suffix == ".csv":
        return benedict.from_csv(text)
    raise ValueError(f"Unsupported file extension: {suffix}")


# ─────────────────────────────────────────────────────────────────────────────
# 2. Safe access helpers
# ─────────────────────────────────────────────────────────────────────────────

def get(b: benedict, path: str, default: Any = None) -> Any:
    """Access a keypath with a default. Alias for b.get(path, default)."""
    return b.get(path, default)


def require(b: benedict, path: str) -> Any:
    """Access a keypath; raise KeyError if missing."""
    val = b.get(path)
    if val is None:
        raise KeyError(f"Required key missing: {path!r}")
    return val


def pluck(b: benedict, *paths: str, default: Any = None) -> dict[str, Any]:
    """Extract multiple keypaths into a flat dict."""
    return {path: b.get(path, default) for path in paths}


def first_of(b: benedict, *paths: str, default: Any = None) -> Any:
    """Return the value of the first path that resolves to a non-None value."""
    for path in paths:
        val = b.get(path)
        if val is not None:
            return val
    return default


# ─────────────────────────────────────────────────────────────────────────────
# 3. Merge and combine
# ─────────────────────────────────────────────────────────────────────────────

def deep_merge(*dicts: dict) -> benedict:
    """
    Deep-merge multiple dicts. Later keys override earlier.

    Example:
        merged = deep_merge(defaults, overrides, env_values)
    """
    result = benedict()
    for d in dicts:
        result.merge(d)
    return result


def merge_with_defaults(data: dict, defaults: dict) -> benedict:
    """Apply defaults to data — data values take priority."""
    b = benedict(defaults)
    b.merge(data)
    return b


# ─────────────────────────────────────────────────────────────────────────────
# 4. Transformation helpers
# ─────────────────────────────────────────────────────────────────────────────

def clean(b: benedict, strings: bool = True, dicts: bool = True, lists: bool = True) -> benedict:
    """
    Remove None (and optionally empty string/dict/list) values.
    Returns a cleaned clone (does not mutate b).
    """
    clone = b.clone()
    clone.clean(strings=strings, dicts=dicts, lists=lists)
    return clone


def flatten_dict(b: benedict, separator: str = "_") -> benedict:
    """
    Flatten nested keys into a single-level dict.
    {"a": {"b": 1}} → {"a_b": 1}
    """
    clone = b.clone()
    clone.flatten(separator=separator)
    return clone


def unflatten_dict(b: benedict, separator: str = "_") -> benedict:
    """
    Unflatten a flat dict into a nested structure.
    {"a_b": 1} → {"a": {"b": 1}}
    """
    clone = b.clone()
    clone.unflatten(separator=separator)
    return clone


def subset(b: benedict, keys: list[str]) -> benedict:
    """
    Extract a subset of keypaths into a new benedict.

    Example:
        subset(user, ["id", "profile.email", "settings.theme"])
    """
    return b.subset(keys)


def rename_keys(b: benedict, mapping: dict[str, str]) -> benedict:
    """
    Rename top-level keys according to a mapping dict.
    Returns a clone with renamed keys.
    """
    clone = b.clone()
    for old, new in mapping.items():
        if old in clone:
            clone.rename(old, new)
    return clone


def standardize(b: benedict) -> benedict:
    """
    Standardize all keys: lowercase + underscore.
    {"FirstName": "Alice"} → {"first_name": "Alice"}
    """
    clone = b.clone()
    clone.standardize()
    return clone


def filter_keys(b: benedict, predicate: Callable[[str], bool]) -> benedict:
    """
    Keep only top-level keys where predicate(key) is True.
    """
    keys = [k for k in b.keys() if predicate(k)]
    return b.subset(keys)


# ─────────────────────────────────────────────────────────────────────────────
# 5. Config management
# ─────────────────────────────────────────────────────────────────────────────

def load_config(
    base: dict | str | Path,
    env_prefix: str = "",
    overrides: dict | None = None,
) -> benedict:
    """
    Build an application config from layered sources:
    1. base dict or file path
    2. environment variables with optional prefix
    3. explicit overrides dict

    Example:
        cfg = load_config("config/base.yaml", env_prefix="APP_")
        db_host = cfg["database.host"]
    """
    if isinstance(base, (str, Path)):
        b = load_file(base)
    else:
        b = benedict(base)

    if env_prefix:
        prefix = env_prefix.upper()
        prefix_len = len(prefix)
        env_layer: dict = {}
        for key, val in os.environ.items():
            if key.upper().startswith(prefix):
                clean_key = key[prefix_len:].lower().replace("__", ".")
                env_layer[clean_key] = val
        if env_layer:
            b.merge(env_layer)

    if overrides:
        b.merge(overrides)

    return b


def save_config(b: benedict, path: str | Path) -> None:
    """Save a benedict config to a file (JSON, YAML, or TOML by extension)."""
    p = Path(path)
    suffix = p.suffix.lower()
    if suffix == ".json":
        p.write_text(b.to_json(indent=2), encoding="utf-8")
    elif suffix in (".yaml", ".yml"):
        p.write_text(b.to_yaml(), encoding="utf-8")
    elif suffix == ".toml":
        p.write_text(b.to_toml(), encoding="utf-8")
    else:
        raise ValueError(f"Unsupported extension: {suffix}")


# ─────────────────────────────────────────────────────────────────────────────
# 6. API response helpers
# ─────────────────────────────────────────────────────────────────────────────

def normalize_response(
    response: dict,
    schema: dict[str, str],
    defaults: dict | None = None,
) -> benedict:
    """
    Normalize an API response by remapping keypaths to canonical names.
    schema: {canonical_name: source_keypath}

    Example:
        normalize_response(
            resp,
            {"user_id": "data.user.id", "email": "data.user.contact.email"},
        )
    """
    b = benedict(response)
    result = benedict(defaults or {})
    for canonical, source_path in schema.items():
        val = b.get(source_path)
        if val is not None:
            result[canonical] = val
    return result


def paginated_items(
    response: dict,
    items_path: str = "data",
    total_path: str = "meta.total",
) -> tuple[list[Any], int]:
    """
    Extract items and total count from a paginated API response.
    Returns (items, total).
    """
    b = benedict(response)
    items = b.get(items_path, [])
    total = b.get(total_path, len(items))
    return items, total


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== Keypath access ===")
    data = {"user": {"profile": {"name": "Alice", "age": 30}, "roles": ["admin", "user"]}}
    b = from_dict(data)
    print("name:  ", b["user.profile.name"])
    print("age:   ", b.get("user.profile.age"))
    print("city:  ", b.get("user.profile.city", "N/A"))
    print("role0: ", b.get("user.roles.0"))

    print("\n=== Assign via keypath ===")
    b["user.profile.city"] = "New York"
    print("city now:", b["user.profile.city"])

    print("\n=== Pluck ===")
    extracted = pluck(b, "user.profile.name", "user.profile.age", "user.roles")
    print(extracted)

    print("\n=== Deep merge ===")
    defaults = benedict({"debug": False, "database": {"host": "localhost", "port": 5432}})
    overrides = {"database": {"port": 5433}, "debug": True}
    merged = deep_merge(defaults, overrides)
    print("debug:", merged["debug"], "port:", merged["database.port"])

    print("\n=== Clean ===")
    messy = from_dict({"a": 1, "b": None, "c": "", "d": {"x": None, "y": 2}})
    cleaned = clean(messy)
    print("cleaned:", dict(cleaned))

    print("\n=== Flatten / Unflatten ===")
    nested = from_dict({"db": {"host": "localhost", "port": 5432}, "app": {"debug": True}})
    flat = flatten_dict(nested)
    print("flat:", dict(flat))
    restored = unflatten_dict(flat)
    print("restored db.host:", restored["db.host"])

    print("\n=== Rename keys ===")
    raw = from_dict({"firstName": "Bob", "lastName": "Smith", "emailAddress": "[email protected]"})
    renamed = rename_keys(raw, {"firstName": "first_name", "lastName": "last_name"})
    print("keys:", list(renamed.keys()))

    print("\n=== Standardize ===")
    camel = from_dict({"FirstName": "Carol", "LastName": "White", "IsActive": True})
    std = standardize(camel)
    print("keys:", list(std.keys()))

    print("\n=== from_json / to_yaml ===")
    j = '{"server": {"host": "0.0.0.0", "port": 8080}, "debug": true}'
    cfg = from_json(j)
    print("host:", cfg["server.host"])
    print("yaml:\n" + cfg.to_yaml())

    print("\n=== Keypaths ===")
    small = from_dict({"a": {"b": 1, "c": {"d": 2}}, "e": 3})
    print("all keypaths:", small.keypaths())

For the addict alternative — addict provides attribute-style access to dict keys (obj.a.b) but doesn’t support keypaths as strings, format I/O, or transformation utilities; benedict gives you b["a.b"] string keypath access, from_json/yaml/toml/url parsing, subset/flatten/merge/standardize all in one. For the munch alternative — munch converts dicts to objects with attribute access (m.a.b) and supports serialization; benedict is better when you need keypath string traversal, multi-format file loading, config layering from environment variables, and transformation pipelines without converting to a custom object type. The Claude Skills 360 bundle includes python-benedict skill sets covering from_dict/json/yaml/toml/file creation, get/require/pluck/first_of access helpers, deep_merge/merge_with_defaults, clean/flatten/unflatten/subset/rename_keys/standardize/filter_keys transformation, load_config() with env prefix layering, save_config() multi-format output, normalize_response() API response mapping, and paginated_items() extractor. Start with the free tier to try dict keypath navigation code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free