prouter
Route filesystem paths through pattern -> handler -> pattern rules with visibility.
The idea is simple. You define routes, each one an input pattern, a handler that rewrites a path, and an output pattern the result has to match. prouter walks a directory tree and runs every path through the route whose input pattern matches its basename, keeping track of what it did along the way.
It never modifies the tree it's routing (nothing gets moved or renamed). What you get back is a set of CSVs describing the transform it would apply, so you can look it over before committing to anything.
The tree is walked bottom-up, deepest paths first and the root last. This is deliberate: renaming children before their parents means a directory rename never invalidates paths you haven't reached yet. The CSVs preserve that order, so applying the rows top to bottom is always safe.
If the route-building syntax feels familiar, that's on purpose: it's inspired by LangGraph's way of wiring up nodes.
Install
pip install prouter
Requires Python 3.12+.
Usage
import re
from pathlib import Path
from prouter import GraphBuilder
# patterns for reuse
draft = re.compile(r"(\d+)_draft\.wav")
final = re.compile(r"\d+_final\.wav")
# a handler (node) may only rewrite the basename, if more than the basename is altered that raises a ValueError.
def rename(path: Path) -> Path:
return path.with_name(path.name.replace("_draft", "_final"))
# assures root_path exist, pre-checks for collisions that would occur later in results_folder.
builder = GraphBuilder(root_path=Path("/path/to/draw/from"), results_folder=Path("/Folder/to/save/results"))
# you can't add the same input_pattern twice, a ValueError is raised.
# routes map (input_pattern -> handler -> output_pattern).
builder.add_route(draft, rename, final)
# walk the tree, match routes, apply handlers in memory.
# the namespace changes are simulated and a ValueError is raised if any collisions would occur.
builder.build()
# write the CSV files describing the transformation to the results_folder (see output section below).
builder.save()
[!NOTE] Matching against those patterns is a
fullmatchagainst the whole basename, so a pattern has to account for the entire filename, not just part of it.
Output
save() drops four CSVs into the folder you give it:
routable_paths.csv— matched a route, and the handler's output lined up with the output pattern.problem_paths.csv— matched a route, but the handler's output did not match the output pattern. These are the ones to look at.clean_paths.csv— matched nothing, left alone.routes.csv— the routes you configured, on their own.
The path CSVs share the same columns: path, node, input_pattern, output_pattern, new_path. routes.csv just has input_pattern, node, output_pattern.
[!NOTE] In those columns, things show up under the names you gave them. Handlers use the function's
__name__, sorenamelands in the CSV asrename. Patterns are trickier, since a compiled regex has no name of its own, so prouter peeks at the calling frame and recovers the variable you bound it to:draftandfinalabove come out asdraftandfinal. Pass a barere.compile(...)inline with no variable and it falls back to the raw regex source.
Metadata
Release files for prouter 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| prouter-0.2.0.tar.gz | 26.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| prouter-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.7 kB
Release files / prouter-0.2.0.tar.gz
| Download URL | prouter-0.2.0.tar.gz |
|---|---|
| Size | 26.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a797c9d7a8d550f76455526a9e140fc464294ec4002381411ecf414ae7c05f9d
|
|
BLAKE2b-256 checksum How to use checksums |
92a0875388eac1576f04a77bdda4a622a99b978f6a56708d5a661b716a809076
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 8, 2026.
Transparency logRelease files / prouter-0.2.0-py3-none-any.whl
| Download URL | prouter-0.2.0-py3-none-any.whl |
|---|---|
| Size | 9.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
79f5f801fda963edc0b76b31fe4acdc2f40b209dbb6e17d5d30f6fd67f5169db
|
|
BLAKE2b-256 checksum How to use checksums |
51fa5edae8c860d20855b0b7ac89c3af3136c021b14c7a7c87a9b4b29f92ff32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 8, 2026.
Transparency logSecurity for prouter 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for prouter-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 8, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.