boltons review
Boltons 26.1.0 is a collection of more than 230 pure Python helpers arranged as separate modules rather than one top-level toolkit. `iterutils` handles chunking, windows, backoff, and recursive `remap`; other modules cover atomic file replacement, bounded caches, ordered multimaps, URLs, strings, tracebacks, and time values. The current release fixes `AtomicSaver` with `os.PathLike`, preserves all values when copying `OrderedMultiDict`, corrects two `IndexedSet` edge cases, fixes `singularize` for words ending in `ss`, and speeds up `MultiReplace`. Our install found no dependencies and no typing marker, so the attraction is inspectable runtime code, not a typed facade or framework convention.
Boltons 26.1.0 installed in 0.4 seconds and occupied 1 MB with 0 dependencies and 0 audit findings in our sandbox, making it a low-cost source of specific missing utilities. Install it for a named helper such as `remap` or `atomic_save`; skip it when modern Python or a focused domain package already covers the job.
We installed it
| Install | ✓ · 0.4s | 1 package on disk · 1 MB |
| Import | ✓ | import boltons in 0.02s · pure Python · requires Python >=3.7 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does boltons install cleanly?
Yes. In a fresh container with an empty cache, pip install boltons finished in 0.4s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does boltons need to run?
Python >=3.7, and nothing compiled: it is pure Python. In our run import boltons succeeded in 0.02s.
boltons or more-itertools: which should you use?
more-itertools: Choose it when the requirement is specifically iterator recipes and recipes compatible with itertools. Boltons 26.1.0 installed in 0.4 seconds and occupied 1 MB with 0 dependencies and 0 audit findings in our sandbox, making it a low-cost source of specific missing utilities.
When should you not use boltons?
Python already has the helper you need, such as itertools.pairwise or functools.cached_property. A second spelling makes maintenance harder without adding behavior.
Use it if
- You need `remap` to walk and rebuild nested mappings and sequences while controlling which values stay.
- Your service needs local atomic file replacement, an in-process LRU cache, or an ordered multimap without adopting a larger framework.
- You want to import one focused pure Python module and may later vendor that module under the BSD license.
- Your supported Python range reaches back to 3.7 and a newer standard-library equivalent is unavailable there.
- Python already has the helper you need, such as `itertools.pairwise` or `functools.cached_property`. A second spelling makes maintenance harder without adding behavior.
- Static type coverage is a release requirement. Our 26.1.0 wheel had no `py.typed` marker, so strict checkers cannot treat the installed package as a fully typed dependency.
- You need a specialized cache with TTL policies shared across processes. `boltons.cacheutils` supplies in-process mappings and does not provide a networked cache server.
- Your URL handling sits on a security boundary. `urlutils` is a general URL model, while authentication callbacks, redirect allowlists, and browser-standard parity require application checks.
- You plan to copy a module and forget where it came from. The README permits vendorization, but your copy then misses upstream fixes unless you track its source release and retain the license.
Setup reality
We installed boltons 26.1.0 in a fresh Python 3.12 Bookworm sandbox. The install finished in 0.4 seconds, left 1 package using 1 MB on disk, and pulled 0 direct dependencies. import boltons completed in 0.02 seconds. pip-audit found 0 known vulnerabilities. The wheel is pure Python, requires Python 3.7 or newer, and does not ship py.typed.
Installation needs no account, service, environment variable, or project config. The work starts at module selection: import boltons.iterutils, fileutils, or another named module instead of expecting a curated API from boltons itself. Version 26.1.0 uses calendar versioning, so the leading 26 is a year-based release line rather than a semantic-major warning.
Vendoring is an explicit option because individual modules are designed to stand alone. Record the 26.1.0 source release and keep the BSD notice if you copy one. A normal package dependency makes security and behavior fixes easier to receive; a copied module leaves that comparison to your team.
Runtime details vary by helper. chunked returns materialized lists, while chunked_iter streams. cachedproperty stores its result on the instance. LRU stays inside one process, and atomic_save protects replacement of one local path rather than a database write or multi-file transaction.
Patterns
Collect an iterable into batches chunk-items
from boltons.iterutils import chunked
pages = chunked(range(10), 4)
# [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]]`chunked` builds a list of lists. Use `chunked_iter` when retaining every batch would waste memory.
Process batches lazily stream-chunks
from boltons.iterutils import chunked_iter
for batch in chunked_iter(read_rows(), 100):
write_batch(batch)`chunked_iter` consumes the source as iteration advances, so a one-shot input cannot be restarted.
Keep the first record for each email deduplicate-records
from boltons.iterutils import unique
clean = unique(rows, key=lambda row: row['email'].casefold())`unique` retains the first value for each hashable key returned by the callback.
Remove secrets from nested data walk-nested-data
from boltons.iterutils import remap
def keep(path, key, value):
return key not in {'password', 'access_token'}
public = remap(payload, visit=keep)A false result from `visit` drops the current item. `enter` and `exit` are available when container construction also needs control.
Create capped retry delays calculate-backoff
from boltons.iterutils import backoff
delays = backoff(0.25, 8.0, count=6, factor=2.0, jitter=True)`backoff` returns delay values only. The caller still decides which failures qualify and performs the sleep.
Write a local file through a temporary path replace-file-atomically
from boltons.fileutils import atomic_save
with atomic_save('state.json', text_mode=True, overwrite=True) as output:
output.write(encoded_state)Version 26.1.0 accepts `os.PathLike` destinations. Atomic replacement covers one filesystem target, not several external operations.
Keep a fixed-size LRU mapping bound-cache
from boltons.cacheutils import LRU
profiles = LRU(max_size=512)
profiles['user:42'] = load_profile(42)
value = profiles.get('user:42')`LRU` is local to one Python process and has no shared invalidation or persistence.
Cache one computed attribute memoize-property
from boltons.cacheutils import cachedproperty
class Invoice:
@cachedproperty
def total(self):
return sum(line.amount for line in self.lines)`cachedproperty` stores the first computed value on that instance. Mutation of `lines` does not refresh it automatically.
Preserve repeated header values store-duplicate-keys
from boltons.dictutils import OrderedMultiDict
headers = OrderedMultiDict()
headers.add('Set-Cookie', 'theme=dark')
headers.add('Set-Cookie', 'session=abc')
cookies = headers.getlist('Set-Cookie')`getlist` retrieves every value for a repeated key. Version 26.1.0 also fixes shallow and deep copies that previously collapsed values.
Normalize text for a URL segment make-slug
from boltons.strutils import slugify
slug = slugify('Café inventory: Q3', delim='-', ascii=True)`slugify` normalizes text but does not prevent collisions, so store a separate stable identifier when uniqueness matters.
Turn a written duration into timedelta parse-duration
from boltons.timeutils import parse_timedelta
retention = parse_timedelta('2 weeks 3 days 4 hours')`parse_timedelta` represents elapsed time. It does not apply calendar time zones or month-length rules.
Separate omitted input from None mark-missing-value
from boltons.typeutils import make_sentinel
MISSING = make_sentinel('MISSING', var_name='MISSING')
def patch(value=MISSING):
return 'unchanged' if value is MISSING else valueCompare a sentinel by identity. Supplying `var_name` gives the object a stable module-level name for representation and pickling.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| more-itertools | PyPI | Choose it when the requirement is specifically iterator recipes and recipes compatible with `itertools`. |
| toolz | PyPI | Choose it for functional composition, currying, and lazy sequence pipelines. |
| cachetools | PyPI | Choose it when cache eviction policies, TTL behavior, and memoizing decorators are the whole problem. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

