This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Rebulk is a Python library for performing advanced string matching using composable patterns (string, regex, functional) and a rule engine. It is published on PyPI as rebulk.
This project is managed with uv. Tooling lives in the
dev dependency group; regex is the optional native extra. Dependencies are pinned in uv.lock.
# Sync the dev environment (creates .venv from uv.lock, with the regex backend)
uv sync --extra native
# Run all tests (also runs module doctests + README.md doctests, see pyproject.toml addopts)
uv run pytest
# Run a single test file
uv run pytest rebulk/test/test_rebulk.py
# Run a single test
uv run pytest rebulk/test/test_rebulk.py::test_function_name -v
# Lint + format check (ruff)
uv run ruff check rebulk
uv run ruff format rebulk
# Type check (mypy)
uv run mypy
# Build sdist + wheel (uv build backend)
uv build
# Multi-version testing (tox via tox-uv: uv provisions each interpreter from the lock)
uv run tox
# Pre-commit hooks (local hooks running the dev-group tools via `uv run`)
uv run pre-commit run --all-files
# Run the suite against the `regex` backend (see remodule.py)
REBULK_REGEX_ENABLED=1 uv run pytest
# Run the suite with the declared-key value_type contract check on (see debug.py)
REBULK_CHECK_DECLARED_KEYS=1 uv run pytestCI runs the full matrix twice — with REBULK_REGEX_ENABLED set to 0 and 1 — so changes touching pattern matching must pass under both the stdlib re and the regex backend.
The library is built around a pipeline: Patterns -> Matches -> Rules.
-
rebulk.py/Rebulk- Main entry point. Inherits fromBuilder, holds patterns, rules, and child Rebulk objects.matches(string, context)runs the full pipeline: pattern matching then rule execution. -
builder.py/Builder- Fluent API mixin providing.string(),.regex(),.functional(), and.chain()methods that create Pattern objects with configurable defaults/overrides. -
pattern.py-Patternabstract base with three implementations:StringPattern- usesstr.findRePattern- usesre.finditerFunctionalPattern- user-provided callable Each pattern producesMatchobjects and applies validators, formatters, and pre/post match processors.
-
chain.py/Chain- Ordered composition of patterns with repeaters (like regex quantifiers?,*,+,{n,m}).Chainis aPattern(matchable); it is assembled through aChainBuilder(inbuilder.py, returned byBuilder.chain()), which appendsChainPartobjects to it. (BuilderandChainBuildershare aPatternFactorybase for the build/defaults machinery.) -
match.py-Match(a single match with start/end/value/name/children) andMatches(a list with indexed lookups by name, tag, start, end position).MatchesDictconverts matches to an OrderedDict. -
rules.py- Rule engine.Rulehaswhen(matches, context)/then(matches, when_response, context). Built-in consequences:RemoveMatch,AppendMatch,RenameMatch,AppendTags,RemoveTags. Rules are topologically sorted bypriorityanddependency. -
processors.py- Default rules:ConflictSolver(keeps longer match on overlap) andPrivateRemover(strips private matches from final output). Priority constantsPRE_PROCESS/POST_PROCESS. -
remodule.py- Conditional import: usesregexmodule instead ofrewhenREBULK_REGEX_ENABLED=1env var is set. Enables repeated captures support. -
validators.py- Reusable validator functions (e.g., surrounding character checks). Designed to be used withfunctools.partial. -
introspector.py- Introspection utilities to extract pattern/rule metadata from a configured Rebulk.
- Fluent API: all builder methods return
selffor chaining. contextdict flows through the entire pipeline (patterns, rules) enabling conditional behavior.- Patterns can be disabled via a
disabled(context)callable. - Rebulk objects can be nested via
.rebulk()to compose pattern sets. markermatches live in a separateMatches.markerssequence, available to rules but excluded from final results.- The
regexPyPI package is an optional dependency (thenativeextra inpyproject.toml), enabled at runtime via env var.
- Conventional Commits are enforced. CI runs
commitlinton every push/PR, and releases are cut automatically bypython-semantic-releasefrom commit types (feat:,fix:,chore:, etc.). Non-conforming commit messages fail the pipeline. The version is the single sourcepyproject.toml:project.version(kept mirrored inrebulk/__version__.py) and is bumped by the release tooling — do not edit it by hand. - Doctests run as part of the default
pytestinvocation: module docstrings (--doctest-modules) and theREADME.mdexamples (--doctest-glob). Keep examples version-stable across the supported Python range (e.g. avoid relying onOrderedDictrepr, which changed in 3.12). - Linting/formatting is ruff with an extended rule set (
E,W,F,I,UP,B,C4,SIM,PIE,RET,ISC,TC,FA,PT,RUF). A.pre-commit-config.yamlruns ruff + mypy + commitizen aslocal/systemhooks viauv run, so they use the exact versions pinned in thedevgroup /uv.lock. - The entire codebase (library + tests) is fully typed and
mypyruns in strict mode (uv run mypy). The package ships apy.typedmarker (PEP 561), so keep new code annotated and strict-clean. - Close issues from the PR/commit that resolves them with a
Closes #Nline (one per issue) in the PR body or commit message, so GitHub auto-closes them on merge to the default branch.