Skip to main content

Towel

“A towel ... is about the most massively useful thing an interstellar hitchhiker can have.”

Douglas Adams, The Hitchhiker's Guide to the Galaxy

Towel finds repeated Python code and extracts it into shared helper functions. It checks each extraction, preserves the parts that differ as parameters, and leaves meaningful names for you to choose.

Release status: 1.948 (beta). This version repairs four silent dry miscompilations found in 1.947 and corrects CLI help, verification-cost reporting and progress output. See the 1.948 changelog and known limitations. Completed validation and publication records are available in the GitHub release history and PyPI package history. Dated preparation records below retain their original release and source identities.

Published 1.947

Towel 1.947 was published October 26, 2026 on PyPI and GitHub from commit 8a853126f5499eb11dfa04fbe304dc332dc5ef73. The 1.947 overview and changelog describe binding-safe renaming, lower candidate-enumeration costs, preservation of each caller's captured lookup mapping, each file's formatting policy and explicit rename consumer scope. The builtin-mapping guard also avoids repeated scans of large unchanged modules within an analysis. Narrow or unmarked rename targets may now require a project-root rerun or an explicit --complete-scope declaration.

The release completed its local gates and exact-commit GitHub CI. All 141 corpus projects completed: 89 PASS, 45 NO_CHANGE, five reviewed import-ambiguity refusals and two known warning-location limitations. There were no phase timeouts or signal terminations. Differential fuzzing completed 9,400 runs with zero failures and 30 inconclusive cases. The published wheel and source archive matched the validated hashes; a fresh PyPI installation and all 22 version-pinned README documentation links were verified. The release notes record the final outcomes, qualifications and controlled comparison with 1.946.

Historical evidence from 1.947 preparation

The following checkpoints describe earlier candidates; the completed release above supersedes their pending status without changing their recorded results.

At the October 19, 2026 preparation checkpoint, 1.947 had not been published. The preceding repair source 2027689, still numbered 1.946, passed its Linux Python 3.13 just ci run: 10,901 tests and 45 subtests, 226 skips and 94% coverage. Those are prior-source repair checks. The final 1.947 source and artifacts still required their own complete release gates at that checkpoint. A subsequent candidate, 59aafb1, passed its interpreter matrix and other scoped release checks, but its corpus exposed repeated large-module scanning. That corpus was stopped intentionally; its results do not validate the later runtime repair. The performance guide records the finding without claiming a measured speedup for the fix. Final validation and publication outcomes belong to the external release record and PyPI. See the readiness report and release checkpoint.

Historical evidence from 1.946 preparation

The following measurements retain their original sources and environments; they do not validate 1.947.

An earlier development audit at 9d57b0d passed 10,583 tests and 45 subtests, with 32 skips and 93.478% coverage. Its six consumer checks preserved their original test outcomes and expected generated outputs. These results precede the 1.946 metadata and documentation update; they do not certify the final versioned artifacts. See the readiness report for source-bound evidence and its limits. The October 18 local validation records the full Python 3.11–3.13 runs, 93–94% coverage, byte-identical CLI outputs and the remaining process-observer limitation.

The October 18 profile of 0b3494c measured Rich 7.6% slower than 1.792 (97.4/97.6 versus 90.5/90.7 seconds, shared macOS host, Python 3.12). Click's noisier difference includes a fifth extraction where 1.792 made four. That profile predates scoped source-correspondence memoization, implemented in subsequent 1.946 source. It reuses a proof only for an owned immutable tree within one analysis; caller trees and materialization retain fresh checks. No new timing benefit is claimed. See where the remaining time goes.

The earlier October 10 container cohorts use versioned 1.946 source a6dc6ed: Voluptuous averaged 87.57 versus 90.98 seconds (3.75% lower), while Click averaged 58.19 versus 47.16 seconds (23.39% slower). These are two shared-host samples per source per workload; Rich has no actual sample in that container campaign. Its full release gates and exact-commit CI were incomplete; the October 18 native profile above is a separate measurement. The portable record binds all eight actual samples, identities, outputs and limits. These results predate the subsequent backslash-parity repair. The later prepared 1.946 runtime is not certified by those earlier source-bound cohorts.

The earlier October 10 shared-host comparison of 9d57b0d with released 1.792 measured the complete cold CLI: Click averaged 56.69 versus 46.53 seconds (21.85% slower), and Rich averaged 177.70 versus 99.77 seconds (78.10% slower), with two samples per version per workload. The performance guide records all samples, CPU time, workload differences and measurement limits. README documentation links target the v1.948 source snapshot. Dated preparation records retain the status of their original checkpoints. The historical 1.947 GitHub release records that version's completed publication and validation.

Start with the Quick start, or browse the documentation index.

Install

The PyPI package is code-towel; the command is towel. The PyPI name towel belongs to an unrelated project, so pip install towel and uvx towel will not install this tool.

pip install code-towel
towel --version
towel --help

The runtime uses only the standard library. Optional tools format inserted code and annotate and type-check generated helpers:

pip install "code-towel[format,types]"

Towel uses these tools when installed; --no-format and --no-types turn either behavior off. Update with pip install --upgrade code-towel, or run without installing with uvx --from code-towel towel --help.

What it does

Given two functions that share a block:

def order_summary(order, label="Order"):
    items = [i for i in order.items if i.in_stock]
    subtotal = sum(i.price for i in items)
    total = round(subtotal * 1.08, 2)
    return f"{label} {order.id}: ${total}"

def quote_summary(quote, label="Quote"):
    items = [i for i in quote.items if i.in_stock]
    subtotal = sum(i.price for i in items)
    total = round(subtotal * 1.08, 2)
    return f"{label} {quote.id}: ${total}"

Towel proposes a helper and rewrites both callers:

def __extracted_func_0(__param_0, label, _towel_owner):
    items = [i for i in __param_0.items if i.in_stock]
    subtotal = sum((i.price for i in items))
    total = round(subtotal * 1.08, 2)
    return f'{label} {__param_0.id}: ${total}'


def order_summary(order, label="Order"):
    _towel_arguments = [(label, order)]
    del order
    del label
    return __extracted_func_0(_towel_arguments[0][1], _towel_arguments[0][0], _towel_arguments.pop())

def quote_summary(quote, label="Quote"):
    _towel_arguments = [(label, quote)]
    del quote
    del label
    return __extracted_func_0(_towel_arguments[0][1], _towel_arguments[0][0], _towel_arguments.pop())

The argument box and final holder preserve the original argument cleanup order when the entire body moves into a helper. The holder can be unread in the helper: keeping those references alive is its purpose. Equal-looking class arguments may instead be lookup suppliers, so a callback or another module can change what each original read resolves. See argument evaluation. Partial extractions whose owned values would cross frames without this proof are declined.

The shared structure becomes the helper's body; differing expressions become parameters. Towel verifies that substituting each call's arguments into the helper reproduces the block it replaces. It also checks binding, control flow and evaluation order, declining transformations that fail those checks.

Generated names are deliberate placeholders. The naming guide shows how to rename them as a checked batch, optionally with a coding assistant.

Use

Preview, refactor into a copy, review the diff, and run your project's tests:

# Complete checked and formatted preview; input stays unchanged.
towel preview path/to/project

# Write the result into a new directory.
towel dry path/to/project path/to/cleaned --no-interactive

# Review before adopting the result.
diff -ru path/to/project path/to/cleaned

The output directory must not already exist or overlap the input. By default, helpers are shared within one module. --cross-module also shares them across modules, adding imports between them. For a faster partial structural listing, use towel preview path/to/project --quick.

The command-line guide covers in-place changes, exclusions, limits, diagnostics and recovery.

Requirements

Python 3.11 to 3.13 on a POSIX system (macOS or Linux). Applying changes needs POSIX filesystem semantics. Parallel analysis uses the fork start method; under other start methods analysis runs on a single core. Windows is not a supported or validated release platform.

One core is enough; TOWEL_WORKERS=1 limits analysis to one worker. Memory, disk use and run time depend on the project and enabled tools. See requirements and resources and performance measurements for measured workloads and their conditions.

Checks and limitations

Towel's soundness requirement is to preserve the behavior of programs that do not use reflection or self-instrumentation, including through code they call. An accepted transformation that changes such a program's behavior is a bug; Towel must fix the transformation or refuse it.

Reflection and source, AST, bytecode, frame or namespace inspection are outside its preservation guarantee, as is instrumentation that uses them to transform functions or classes. Towel does not scan for these behaviors or refuse code to protect them; decorators, ordinary calls and hooks have the same boundary. Protect sensitive definitions with # towel: no-extract immediately after the signature's final colon. The function opt-out guide explains its placement and limits. Mark the frame whose identity matters, including when its callee inspects it. The marker preserves that definition's source, not module namespaces, absolute line numbers or unmarked call chains. Review the known limitations and run your tests before adopting changes.

In annotated projects, Towel uses the configured type checkers when available and preserves caller-side narrowing. Existing checker errors are compared against a baseline; a checker that cannot run refuses typed extraction. The typing guide explains this policy and the unverified --no-types option.

Documentation and development

The documentation index groups tutorials, task guides, technical reference, design decisions and release evidence. Contributors can start with development setup and checks; release maintainers should follow the release procedure. Report security issues through the security policy.

License

Towel is licensed under the Apache License 2.0; its source files carry Eric Allen copyright headers.

Metadata

Release files for code-towel 1.948

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for code-towel 1.948
File Size Uploaded Provenance Actions
code_towel-1.948.tar.gz 7.0 MB Without provenance Details for code_towel-1.948.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for code-towel 1.948
File Interpreter ABI Platform Actions
code_towel-1.948-py3-none-any.whl Python 3 none any Details for code_towel-1.948-py3-none-any.whl

Total release size: 7.8 MB

Release files / code_towel-1.948.tar.gz

Download URL code_towel-1.948.tar.gz
Size 7.0 MB
Tags Source
SHA-256 checksum
How to use checksums
352fc5fabb2b66fd20ea1873cfc344aed02d768703311aa814e5e1028af0e9b2
BLAKE2b-256 checksum
How to use checksums
de081496188fae1bc59deeb920c248978b63ccfbb670ac0461fdf276e0d8becd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / code_towel-1.948-py3-none-any.whl

Download URL code_towel-1.948-py3-none-any.whl
Size 837.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
980da6fc5fce3c4470651c7d0a1908a0a9b65b8f5129e0eeec51bacc37afa394
BLAKE2b-256 checksum
How to use checksums
9abddf5aa622ecb2a2a954d27303acc98b754ee1fb9105588a86fb80dfd6b11c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Security for code-towel 1.948

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A 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.

Release history Release notifications | RSS feed

This release

1.948 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page