bracex
Bash-style brace expansion for Python, matching real Bash output down to its edge cases.
Repository Health
Technical Analysis
Bracex is a Python library that implements Bash-style brace expansion, turning patterns like {a,b,c} and {1..10} into the full list of resulting strings, the same way Bash expands them before running a command. It supports comma-separated lists, numeric and alphabetic ranges with custom increments and zero-padding, nested groups, and backslash escaping, and its test suite is validated directly against real Bash 4.3 output rather than a hand-written spec.
The library ships both as an importable API (bracex.expand() / bracex.iexpand()) and as a command-line tool (python -m bracex), and is used internally by other Python libraries such as wcmatch to power glob-style pattern matching. It is fully typed (py.typed), has zero runtime dependencies, and targets Python 3.10+.
What You Get
- A single
expand()/iexpand()API that turns a brace pattern into a list or a lazy iterator of expanded strings - Support for comma-separated lists (
{a,b,c}), numeric ranges with increments ({1..10..2}), and alphabetic ranges ({a..z}) - Automatic zero-padding preservation for numeric ranges (
{01..10}stays zero-padded across all generated values) - A configurable expansion limit that raises
ExpansionLimitExceptionto guard against combinatorial explosion on malformed input - A
python -m bracexcommand-line tool for expanding patterns directly from the shell - Full type hints (
py.typed) for static type checking in consuming projects
Common Use Cases
- Expanding user-supplied glob-like patterns before passing them to a file-matching library
- Generating batches of directory or file names programmatically (e.g.
{a,b}/{1..2}produces 4 paths) - Building test-case matrices from compact bracket notation instead of writing out every combination by hand
- Implementing Bash-compatible CLI argument or pattern expansion in a Python-based tool
- Powering pattern-matching libraries like wcmatch that need Bash-faithful brace semantics
Under The Hood
Architecture
The library centers on a single-pass recursive-descent parser: StringIter provides a lookahead/rewind cursor over the input string, ExpandBrace.get_literals gathers literal text up to brace boundaries while get_sequence recursively handles the contents between { and }, and get_range short-circuits into dedicated numeric/alphabetic range handlers (get_int_range, get_char_range) before falling back to comma-separated group parsing. Results are combined lazily through generator-based squash/chain/flatten helpers that build the Cartesian product of all literal and group segments without materializing intermediate lists, and an account() limit check runs at every combination point to abort pathological expansions early. The public expand/iexpand functions are thin wrappers that instantiate a fresh ExpandBrace per call and implement bytes-vs-str dispatch by decoding to and re-encoding from latin-1. Because parsing state lives on the ExpandBrace instance rather than being passed explicitly, the traversal is compact but non-trivial to modify without breaking the invalid-group fallback branches that reconstruct literal {/} text when a candidate group turns out not to be a valid sequence.
Tech Stack
Bracex is pure Python with no runtime dependencies, built with hatchling (dynamic versioning sourced from bracex/__meta__.py via a custom hatch hook) and targeting Python 3.10+. Development tooling is comprehensive: mypy --strict for type checking, ruff for linting with an extensive rule selection, pytest/pytest-cov/coverage for testing, and a tox matrix declared inline in pyproject.toml that runs the full suite plus documentation builds. Documentation is generated with zensical from Markdown sources, and pyspelling checks prose spelling as part of the doc build. The package ships a py.typed marker for downstream type-checking and exposes a python -m bracex console entry point via argparse.
Code Quality
Testing is extensive and unusually rigorous for the library’s size — the core test module drives dozens of parametrized cases plus a large corpus of Bash-generated fixtures that were captured directly from running real Bash 4.3, so the suite validates output equivalence against the reference implementation rather than only hand-written expectations. mypy --strict is enforced project-wide, with pragma: no cover used sparingly and deliberately for genuinely unreachable branches. Error handling favors explicit custom exceptions over silent truncation, and CI runs the full matrix across five Python versions and two platforms with coverage uploaded to Codecov, giving strong confidence that platform-specific string and regex behavior is exercised.
What Makes It Unique
Brace expansion itself is a well-trodden feature — minimatch, wcmatch’s own bundled logic, and various shell-emulation libraries all implement variants of it — so bracex’s novelty isn’t the concept but its fidelity: the project systematically diffs its output against real Bash execution rather than relying on a written spec, catching the numerous undocumented edge cases in Bash’s actual behavior (empty slots, invalid groups falling back to literal text, zero-padded negative ranges) that ad hoc reimplementations typically get wrong. The public API is deliberately minimal — two functions plus a limit safety valve — which keeps it easy to embed as a dependency without imposing an opinionated interface on callers.