Funcy
A fancy and practical collection of functional programming tools for Python, from collection walking to control-flow decorators.
Repository Health
Technical Analysis
Funcy is a pure-Python, zero-dependency toolkit of functional utilities inspired by Clojure and Underscore. It covers three broad areas: collection operations (merge, walk, select, group_by, flatten and their type-preserving variants across dicts, sets, lists and iterators), function composition and currying (partial, curry, compose, complement, all_fn), and control-flow decorators that turn common patterns like retrying, rate-limiting, memoizing, and suppressing exceptions into single-line annotations.
The library is organized as a set of focused, single-purpose modules (colls, funcs, seqs, decorators, flow, objects, debug, strings, tree, calc, primitives, types, funcolls) that are re-exported through a flat top-level namespace, so from funcy import whatever_you_need works without knowing which submodule it lives in. It has no runtime dependencies, supports Python 3.4 through 3.13 plus PyPy3, and has been actively maintained since 2012 with a large surface area documented via a dedicated cheatsheet and Sphinx docs site.
What You Get
- Type-preserving collection operations — merge, walk, select, and group_by work identically across dicts, sets, lists, tuples, and even strings, always returning the same type they were given
- A
@decoratorhelper that turns a plain function into a proper decorator (with functools.wraps semantics) in one line, instead of hand-rolling wrapper boilerplate - Ready-made control-flow decorators — @retry, @limit_error_rate, @ignore, @once, and print_durations/print_exits for debugging without adding logging calls everywhere
- Function tools for point-free style — partial, rpartial, curry, rcurry, compose, complement, and all_fn/any_fn for building predicates from smaller pieces
- Nested-structure helpers — get_in, set_in, update_in, del_in, and has_path for reading and writing deep dict/list paths without manual traversal
- Zero runtime dependencies and broad interpreter support (CPython 3.4-3.13, PyPy3), keeping it safe to add to any project without pulling in a dependency tree
Common Use Cases
- Merging and transforming configuration dicts or API response payloads without writing custom merge logic for each shape
- Wrapping unreliable I/O calls (HTTP requests, external services) with @retry and @limit_error_rate instead of writing bespoke try/except loops
- Building small composable predicates for filtering and validation with complement, all_fn, and the select/lwhere family
- Reading and writing deeply nested JSON-like structures (e.g. app config, GraphQL responses) via get_in/set_in without manual key-chasing
- Writing custom decorators quickly with @decorator instead of hand-writing functools.wraps boilerplate for every new decorator
Under The Hood
Architecture
Funcy is organized as a flat set of single-concern modules — colls.py, funcs.py, seqs.py, decorators.py, flow.py, objects.py, debug.py, strings.py, tree.py, calc.py, primitives.py, types.py, and funcolls.py — each declaring its own __all__ and getting re-exported through funcy/__init__.py, which concatenates every module’s __all__ into one flat public namespace via lcat(sys.modules['funcy.' + m].__all__ for m in modules). There are almost no classes; the core abstraction is the Call object used by the @decorator helper in decorators.py, which wraps a function invocation so decorator authors can inspect call._func/call._args and invoke call() when ready. Collection operations in colls.py use a _factory() dispatcher keyed on type(coll) (with special-casing for defaultdict, dict views, and iterators) so that operations like walk and merge can stay generic across dicts, sets, lists, and strings while preserving the caller’s original type.
Tech Stack
The library has zero runtime dependencies — everything is built on the Python standard library (itertools, collections.abc, functools, contextlib, inspect, operator). Packaging uses a plain setuptools setup.py with the version read from a standalone VERSION file. Documentation is built with Sphinx (docs/ directory, published to Read the Docs) and includes a dedicated cheatsheet page. CI runs on GitHub Actions with a version matrix covering CPython 3.5 through 3.13 plus PyPy3, alongside a separate flake8 lint job and a docs-build job with -W (warnings as errors).
Code Quality
Every module has a dedicated test file (test_colls.py, test_funcs.py, test_decorators.py, etc.) plus a test_interface.py that checks the public API surface, and separate py38_decorators.py/py38_funcs.py files isolate syntax that requires newer Python versions. flake8 is enforced in CI against both the library and the test suite. The code has no type hints and relies on flake8 rather than mypy for static checking, but naming is consistent and terse throughout (l-prefixed variants like lmap/lfilter for list-returning versions of lazy iterator functions is a clear, deliberate convention).
API Design
The library’s defining trait is ergonomic, guessable naming: l-prefixed functions return lists instead of iterators, r-prefixed functions flip the first-argument convention (rpartial, rcurry), and one-word verbs (walk, select, join, merge) read naturally at call sites. The @decorator helper is the most distinctive piece — it lets you write a decorator as a single function taking a call object instead of writing nested def wrapper(*args, **kwargs) boilerplate, and it automatically supports both @deco and @deco(arg=val) call styles based on the wrapped function’s signature.