Nesting and composition

Nested field patterns

When the substring after : in a field is a balanced nested brace pattern (for example {outer:{inner:d}}), the inner pattern is compiled and matched as part of the outer capture, then parsed again. Nested groups appear as ParseResult objects under ParseResult.named. Maximum nesting depth when compiling is 10.

from formatparse import parse

r = parse("{outer:{inner:d}}", "42")
assert r.named["outer"].named["inner"] == 42

Brace-balanced scanning applies in the spec after :. Literal braces in the pattern string still use {{ and }} for a single literal brace in pattern text.

Composition with composed_type

Use composed_type() to wrap a compiled FormatParser and pass it in extra_types so one field is parsed by the child parser and returns a nested ParseResult.

from formatparse import compile, composed_type

ts = compile("{year:d}-{month:02d}-{day:02d}")
log = compile(
    "{ts:Timestamp} [{level}] {msg}",
    extra_types={"Timestamp": composed_type(ts)},
)
r = log.parse("2024-01-15 [ERROR] oops")
inner = r.named["ts"]
assert inner.named["year"] == 2024

Pickling: a pickled FormatParser stores only the pattern string. After pickle.loads, pass extra_types again when calling parse / search / findall if your pattern uses custom types—including any composed child parsers.

See also Pattern Syntax (nested patterns section) and issues #7, #12.