Library / SDK
Erotemic/ubelt avatar
Erotemic/ubelt

ubelt: a stdlib-shaped companion library for everyday Python

A Python utility library with a stdlib like feel and extra batteries. Paths, Progress, Dicts, Downloads, Caching, Hashing: ubelt makes it easy!

740 stars51 forksPythonApache-2.0

At a glance

What is it?
ubelt is a pure Python utility library of roughly 120 focused functions that behave the same way on Linux, Mac and Windows, from path handling and hashing to caching and progress bars. It is Apache-2.0 licensed, stable, and every function carries a doctest.
Who is it for?
ubelt fits Python codebases that keep rewriting the same path, hashing, caching and progress helpers and want one dependency that behaves identically on Linux, Mac and Windows, with a Python 3.8 floor and Apache-2.0 terms. It does not fit a project that wants a small auditable dependency surface, since the flat namespace pulls in roughly 120 functions at once, and it does not fit hot numeric loops that need compiled speed.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Roughly 120 small functions with one consistent calling style

ubelt is positioned as a standard-library companion rather than a framework. The README describes it as a collection of about 120 focused utilities that make everyday Python tasks shorter and more consistent, and states the goal plainly: provide simple functions for common tasks not yet addressed by the Python standard library. The constraint listed alongside that goal is equally plain, low impact pure Python that is easy to install and use, and the method is that nearly every function is written with a docstring and a doctest. The result is a flat API where everything is reachable from the top-level ubelt namespace, and where the same call behaves the same way on Linux, Mac and Windows apart from small unavoidable platform differences. The audience is application and research Python developers who would otherwise assemble their own set of helpers and then maintain them across three operating systems.

The whole public surface fits in about 40 lines of imports

The clearest statement of the library's shape is the import block that defines the top-level API. The README notes that ubelt is small and that its top-level API is defined using roughly 40 lines, and this excerpt shows the shape of it:

python
    from ubelt.util_arg import (argflag, argval,)
    from ubelt.util_cache import (CacheStamp, Cacher,)
    from ubelt.util_cmd import (cmd,)
    from ubelt.util_dict import (AutoDict, AutoOrderedDict, SetDict, UDict, ddict,

Every module behind the facade is named for its subject, so util_hash holds hashing, util_path holds path handling, util_dict holds the dictionary types and so on. The flat namespace is the deliberate trade-off: you get one import line and one lookup, at the cost of a larger surface to read before you know what the library offers. The documentation answers that partly with a function usefulness chart linked from the README, which ranks the API by how much each function is used in practice.

ProgIter, hashing and caching are the functions people adopt first

The README highlights five entries as the ones ubelt does best, and they are worth looking at as a group because they cover the most common complaint in research and data pipelines. Progress reporting is handled by ub.ProgIter, described as a faster and simpler alternative to tqdm. Hashing is covered by ub.hash_data for in-memory structures such as lists, dicts, ints and strings, and ub.hash_file for files on disk. Caching is ub.Cacher, which caches a block of code, and ub.CacheStamp, which records a timestamp instead of recomputing. Shell commands are handled by ub.cmd, and set-enriched dictionaries by ub.udict. The alternative to each of these is not another library but a small local helper that every project ends up writing slightly differently, which is exactly the duplication the library sets out to remove.

UDict, SetDict and ub.Path extend the standard types in place

Beyond the headline five, the README lists a long set of tasks the API covers, and a few of them show the library's approach to extending standard behaviour without replacing it. The dictionary helpers add methods such as subdict, take, peek_value, invert, sorted_keys and sorted_vals on top of a UDict, while SetDict performs set operations on dictionaries, and AutoDict and AutoOrderedDict cover automatic key creation and ordering. On the path side, ub.Path extends pathlib with expand, ensuredir, endswith, augment and delete, and the platform helpers expose appdir-style locations for data, cache and config directories, plus find_path and find_exe for locating files and executables. Elsewhere there is urepr for a readable string representation of nested structures, color_text for ANSI colouring, hzcat for joining multiline strings horizontally, symlink for cross-platform symlinks, Timer for timing a block, and memoize helpers for functions and properties.

Doctests are the documentation and the test suite at once

The testing strategy is unusual enough to be a design decision rather than an implementation detail. The README states that almost every function in ubelt was written with a doctest, which provides example usage and helps achieve 100% test coverage, with minor exceptions on Windows. The goal of that method is stated too: a baseline level of documentation and testing should always exist, even if functions are later copy-pasted into other libraries. The build configuration backs this up. The pytest options in pyproject.toml enable xdoctest with the google style and disable the standard doctest plugin, and the warning filters name specific cases, including the missing configuration warning raised by the Cacher constructor and a hint about defining a nice repr method. The repository also carries run_doctests.sh, run_linter.sh, run_tests.py and run_developer_setup.sh at the top level, so the same scripts a contributor uses are visible to anyone reading the tree.

Apache-2.0, a Python 3.8 floor, and stable 1.4.x releases

The packaging metadata says what the compatibility story is. The minimum supported Python is 3.8, the project is marked as a stable development status with the Production/Stable classifier, and it is typed with partial type annotations. The licence is Apache 2.0, the build backend is setuptools, and the tool configuration enables trusted publishing to PyPI with direct CI signing. The release history shows steady, low-drama progression rather than frequent churn: v1.4.1 on 2026-02-08, v1.4.2 on 2026-04-13 and v1.4.3 on 2026-07-31. The last push was on 2026-09-27, so work has continued since the most recent tag, and the CHANGELOG.md file at the root is where the details of what changed between those points live. The upstream project states that it has been maintained since 2017, which matters for a dependency that ends up in the import list of many scripts.

Where the flat, pure-Python design stops paying off

Two limits are visible in the project's own constraints. The first is that everything is pure Python with minimal dependencies and fast import, which is exactly what you want in a helper library and exactly what you do not want inside a hot numeric loop, where a compiled implementation would win. The second is the breadth of the surface. With roughly 120 functions behind one namespace, importing ubelt means importing a large chunk of code even if you only need one hash helper, and the names are generic enough that they can collide with names in your own codebase or in another dependency. The README also positions the library as filling gaps the standard library has not filled, which is a moving target: what counts as a gap changes as CPython evolves. ProgIter being pitched as a tqdm alternative is another place where the honest reading matters, since that is the project's own claim about its progress bar rather than an independent measurement.

Editorial conclusion

ubelt fits Python codebases that keep rewriting the same path, hashing, caching and progress helpers and want one dependency that behaves identically on Linux, Mac and Windows, with a Python 3.8 floor and Apache-2.0 terms. It does not fit a project that wants a small auditable dependency surface, since the flat namespace pulls in roughly 120 functions at once, and it does not fit hot numeric loops that need compiled speed. Before adopting it, check the function names against your own helpers to see what you would replace, read the Cacher constructor warning that the project filters in its own test configuration, and confirm that the Python version your project supports is still at or above the 3.8 minimum.

Frequently asked questions

What is ubelt and what does it replace?

ubelt is a pure Python utility library of about 120 functions that extend the standard library with path handling, hashing, caching, progress reporting, shell commands and dictionary helpers. Its stated goal is to provide simple functions for common tasks the Python standard library does not cover, so it usually replaces a project-specific helper module.

Which Python versions does ubelt support?

The packaging metadata sets the minimum Python version to 3.8, and the project is classified as Development Status :: 5 - Production/Stable. The classifiers list Windows, MacOS and POSIX Linux as supported operating systems.

How does ubelt test and document its functions?

Almost every function is written with a doctest, which serves as both the example documentation and the test, and the pytest configuration enables xdoctest with the google style. The project states that this approach helps reach full test coverage, with minor exceptions on Windows.

Is ubelt an alternative to tqdm?

For progress reporting, yes. The README describes ub.ProgIter as a faster and simpler alternative to tqdm, though that is the project's own claim rather than an independent benchmark. The library is otherwise independent of tqdm and covers paths, hashing, caching and dicts.

Official sources

  1. Erotemic/ubelt on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/erotemic-ubelt.svg)](https://hysenlabs.com/projects/erotemic-ubelt)

Was this useful?