The purpose of this document is to list all of the notable changes to this project. The format was inspired by (but doesn’t strictly adhere to) Keep a Changelog . This project adheres to semantic versioning.

Release 4.17 (2018-10-20)

  • Add Python 3.7 to versions tested on Travis CI and using tox and document compatibility with Python 3.7.

  • Add rudimentary caching decorator for functions:

    Over the years I’ve used several variations on this function in multiple projects and I’d like to consolidate all of those implementations into a single one that’s properly tested and documented.

    Due to the simplicity and lack of external dependencies it seemed kind of fitting to include this in the humanfriendly package, which has become a form of extended standard library for my Python projects 😇.

Release 4.16.1 (2018-07-21)

Yet another ANSI to HTML improvement: Emit an ANSI reset code before emitting ANSI escape sequences that change styles, so that previously activated styles don’t inappropriately “leak through” to the text that follows.

Release 4.16 (2018-07-21)

More HTML to ANSI improvements:

  • Added humanfriendly.text.compact_empty_lines() function.
  • Enable optional html_to_ansi(data[, callback]) argument.
  • Added a code sample and screenshot to the HTMLConverter documentation.
  • Emit vertical whitespace for block tags like <div>, <p> and <pre> and post-process the generated output in __call__() to compact empty lines.
  • Don’t pre-process preformatted text using the user defined text callback.
  • Improve robustness against malformed HTML (previously an IndexError would be raised when a closing </a> tag was encountered without a corresponding opening <a> tag).
  • Emit an ANSI reset code when HTMLConverter.close() is called and a style is still active (improves robustness against malformed HTML).

Release 4.15.1 (2018-07-14)

Bug fixes for HTML to ANSI conversion.

HTML entities were being omitted from conversion because I had neglected to define the handle_charref() and handle_entityref() methods (whose definitions are so conveniently given in the documentation of the HTMLParser class 😇).

Release 4.15 (2018-07-14)

Added the ansi_to_html() function which is a shortcut for the HTMLConverter class that’s based on html.parser.HTMLParser.

This new functionality converts HTML with simple text formatting tags like <b> for bold, <i> for italic, <u> for underline, <span> for colors, etc. to text with ANSI escape sequences.

I’m still working on that awesome new project (update: see chat-archive), this functionality was born there but seemed like a useful addition to the humanfriendly package, given the flexibility that this provides 😇.

Release 4.14 (2018-07-13)

Support for 24-bit (RGB) terminal colors. Works by accepting a tuple or list with three integers representing an RGB (red, green, blue) color.

Release 4.13 (2018-07-09)

Support for italic text rendering on the terminal.

I’m working on an awesome new project (update: see chat-archive) that’s almost ready to publish, but then I noticed that I couldn’t render italic text on the terminal using the humanfriendly package. I checked and sure enough my terminal supported it just fine, so I didn’t see any reason not to fix this now 😇.

Release 4.12.1 (2018-05-10)

It was reported in issue #28 that humanfriendly --demo didn’t work on Python 3 due to two unrelated TypeError exceptions. First I added a failing regression test to the test suite (here’s the failing build) and then I applied the changes suggested in issue #28, confirming that both issues are indeed fixed because the test now passes (here’s the successful build).

Release 4.12 (2018-04-26)

  • Make format_timespan() accept datetime.timedelta objects (fixes #27).
  • Add license key to script (pointed out to me in coloredlogs pull request #53).

Release 4.11 (2018-04-26)

Added this changelog as requested in #23.

I’ve held off on having to keep track of changelogs in my open source programming projects until now (2018) because it’s yet another piece of bookkeeping that adds overhead to project maintenance versus just writing the damn code and throwing it up on GitHub :-p. However all that time I felt bad for not publishing change logs and I knew that requests would eventually come in and indeed in the past months I’ve received two requests in #23 and in issue #55 of coloredlogs.

I actually wrote a Python script that uses the git tag and git for-each-ref commands to automatically generate a CHANGELOG.rst “prototype” (requiring manual editing to clean it up) to bootstrap the contents of this document. I’m tempted to publish that now but don’t want to get sidetracked even further :-).

Release 4.10 (2018-03-31)

Added the Timer.sleep() method to sleep “no more than” the given number of seconds.

Release 4.9 (2018-03-28)

Added the format_rst_table() function to render RST (reStructuredText) tables.

Release 4.8 (2018-01-20)

Added the coerce_pattern() function. I previously created this for vcs-repo-mgr and now need the same thing in qpass so I’m putting it in humanfriendly :-) because it kind of fits with the other coercion functions.

Release 4.7 (2018-01-14)

Release 4.6 (2018-01-04)

Fixed issue #21 by implementing support for bright (high intensity) terminal colors.

Release 4.5 (2018-01-04)

Fixed issue #16 by merging pull request #17: Extend byte ranges, add RAM output to command line.

In the merge commit I removed the --format-bytes option that #17 added and instead implemented a --binary option which changes --format-size to use binary multiples of bytes (base-2) instead of decimal multiples of bytes (base-10).

Release 4.4.2 (2018-01-04)

  • Fixed ImportError exception on Windows due to interactive prompts (fixes #19 by merging #20.).
  • Enable MacOS builds on Travis CI and document MacOS compatibility.
  • Change Sphinx documentation theme.

Release 4.4.1 (2017-08-07)

Include the Sphinx documentation in source distributions (same rationales as for the similar change made to ‘coloredlogs’ and ‘verboselogs’).

Release 4.4 (2017-07-16)

Added the make_dirs() and touch() functions to the humanfriendly.testing module.

Release 4.3 (2017-07-10)

Don’t log duplicate output in run_cli().

Release 4.2 (2017-07-10)

Automatically reconfigure logging in run_cli().

Release 4.1 (2017-07-10)

Improve run_cli() to always log standard error as well.

Release 4.0 (2017-07-10)

Backwards incompatible improvements to humanfriendly.testing.run_cli().

I just wasted quite a bit of time debugging a Python 3.6 incompatibility in deb-pkg-tools (see build 251688788) which was obscured by my naive implementation of the run_cli() function. This change is backwards incompatible because run_cli() now intercepts all exceptions whereas previously it would only intercept SystemExit.

Release 3.8 (2017-07-02)

Make it easy to mock the $HOME directory.

Release 3.7 (2017-07-01)

Enable customizable skipping of tests.

Release 3.6.1 (2017-06-24)

Improved the robustness of the PatchedAttribute and PatchedItem classes.

Release 3.6 (2017-06-24)

  • Made the retry limit in interactive prompts configurable.
  • Refactored the makefile and Travis CI configuration.

Release 3.5 (2017-06-24)

Added TestCase.assertRaises() enhancements.

Release 3.4.1 (2017-06-24)

Bug fix for Python 3 syntax incompatibility.

Release 3.4 (2017-06-24)

Promote the command line testing function to the public API.

Release 3.3 (2017-06-24)

  • Added the humanfriendly.text.random_string() function.
  • Added the humanfriendly.testing module with unittest helpers.
  • Define humanfriendly.text.__all__.

Release 3.2 (2017-05-18)

Added the humanfriendly.terminal.output() function to auto-encode terminal output to avoid encoding errors and applied the use of this function in various places throughout the package.

Release 3.1 (2017-05-06)

Improved usage message parsing and rendering.

While working on a new project I noticed that the join_lines() call in render_usage() could corrupt lists as observed here: (check the part after ‘Supported locations include:’)

To be honest I’m not even sure why I added that join_lines() call to begin with and I can’t think of any good reasons to keep it there, so gone it is!

Release 3.0 (2017-05-04)

  • Added support for min, mins abbreviations for minutes based on #14.
  • Added Python 3.6 to supported versions on Travis CI and in documentation.

I’ve decided to bump the major version number after merging pull request #14 because the humanfriendly.time_units data structure was changed. Even though this module scope variable isn’t included in the online documentation, nothing stops users from importing it anyway, so this change is technically backwards incompatible. Besides, version numbers are cheap. In fact, they are infinite! :-)

Release 2.4 (2017-02-14)

Make usage() and show_pager() more user friendly by changing how less as a default pager is invoked (with specific options).

Release 2.3.2 (2017-01-17)

Bug fix: Don’t hard code conditional dependencies in wheels.

Release 2.3.1 (2017-01-17)

Fix parse_usage() tripping up on commas in option labels.

Release 2.3 (2017-01-16)

  • Switch to monotonic clock for timers based on #13.
  • Change to everywhere.
  • Improve intersphinx references in documentation.
  • Minor improvements to setup script.

Release 2.2.1 (2017-01-10)

  • Improve use of timers as context managers by returning the timer object (as originally intended).
  • Minor improvements to reStructuredText formatting in various docstrings.

Release 2.2 (2016-11-30)

  • Fix and add a test for parse_date() choking on Unicode strings.
  • Only use “readline hints” in prompts when standard input is a tty.

Release 2.1 (2016-10-09)

Added clean_terminal_output() function to sanitize captured terminal output.

Release 2.0.1 (2016-09-29)

Update README.rst based on the changes in 2.0 by merging #12.

Release 2.0 (2016-09-29)

Proper support for IEEE 1541 definitions of units (fixes #4, merges #8 and #9).

Release 1.44.9 (2016-09-28)

  • Fix and add tests for the timespan formatting issues reported in issues #10 and #11.
  • Refactor Makefile, switch to py.test, add wheel support, etc.

Release 1.44.8 (2016-09-28)

  • Fixed issue #7 (TypeError when calling show_pager() on Python 3) and added a test.
  • Minor improvements to the script.
  • Stop testing tags on Travis CI.

Release 1.44.7 (2016-04-21)

Minor improvements to usage message reformatting.

Release 1.44.6 (2016-04-21)

Remove an undocumented .strip() call from join_lines().

Why I noticed this: It has the potential to eat significant white space in usage messages that are marked up in reStructuredText syntax.

Why I decided to change it: The behavior isn’t documented and on second thought I wouldn’t expect a function called join_lines() to strip any and all leading/trailing white space.

Release 1.44.5 (2016-03-20)

Improved the usage message parsing algorithm (also added a proper test). Refer to test_parse_usage_tricky() for an example of a usage message that is now parsed correctly but would previously confuse the dumb “parsing” algorithm in parse_usage().

Release 1.44.4 (2016-03-15)

Made usage message parsing a bit more strict. Admittedly this still needs a lot more love to make it more robust but I lack the time to implement this at the moment. Some day soon! :-)

Release 1.44.3 (2016-02-20)

Unbreak conditional importlib dependency after breakage observed here:

Release 1.44.2 (2016-02-20)

  • Make conditional importlib dependency compatible with wheels: While running tox tests of another project of mine that uses the humanfriendly package I noticed a traceback when importing the humanfriendly package (because importlib was missing). After some digging I found that tox uses pip to install packages and pip converts source distributions to wheel distributions before/during installation, thereby dropping the conditional importlib dependency.
  • Added the Sphinx extension trove classifier to the script.

Release 1.44.1 (2016-02-18)

  • Fixed a non-fatal but obviously wrong log format error in prompt_for_choice().
  • Added Python 3.5 to supported versions on Travis CI and in the documentation.

Release 1.44 (2016-02-17)

Added the humanfriendly.sphinx module with automagic usage message reformatting and a bit of code that I’d been copying and pasting between docs/ scripts for years to include magic methods, etc in Sphinx generated documentation.

Release 1.43.1 (2016-01-19)

Bug fix for Python 2.6 compatibility in script.

Release 1.43 (2016-01-19)

Replaced import_module() with a conditional dependency on importlib.

Release 1.42 (2015-10-23)

Added proper tests for ANSI escape sequence support.

Release 1.41 (2015-10-22)

  • Moved hard coded ANSI text style codes to a module level ANSI_TEXT_STYLES dictionary.
  • Improved the related error reporting based on the new dictionary.

Release 1.40 (2015-10-22)

Added support for custom delimiters in humanfriendly.text.split().

Release 1.39 (2015-10-22)

Added the humanfriendly.compat module to group Python 2 / 3 compatibility logic.

Release 1.38 (2015-10-22)

  • Added the prompt_for_confirmation() function to render (y/n) prompts.
  • Improved the prompt rendered by prompt_for_choice().
  • Extracted supporting prompt functionality to separate functions.

Release 1.37 (2015-10-22)

  • Added support for wrapping ANSI escape sequences in “readline hints”.
  • Work around incompatibility between flake8-pep257==1.0.3 and pep257==0.7.0.

Release 1.36 (2015-10-21)

Added message() and warning() functions to write informational and warning messages to the terminal (on the standard error stream).

Release 1.35 (2015-09-10)

Implemented the feature request in issue #6: Support for milleseconds in timespan parsing/formatting. Technically speaking this breaks backwards compatibility but only by dropping a nasty (not documented) implementation detail. Quoting from the old code:

# All of the first letters of the time units are unique, so
# although this check is not very strict I believe it to be
# sufficient.

That no longer worked with [m]illiseconds versus [m]inutes as was also evident from the feature request / bug report on GitHub.

Release 1.34 (2015-08-06)

Implemented and added checks to enforce PEP-8 and PEP-257 compliance.

Release 1.33 (2015-07-27)

Added format_length() and parse_length()` functions via pull request #5.

Release 1.32 (2015-07-19)

Added the humanfriendly.text.split() function.

Release 1.31 (2015-06-28)

Added support for rendering of usage messages to reStructuredText.

Release 1.30 (2015-06-28)

Started moving functions to separate modules.

Release 1.29 (2015-06-24)

Added the parse_timespan() function.

Release 1.28 (2015-06-24)

Extracted the “new” tokenize() function from the existing parse_size() function.

Release 1.27 (2015-06-03)

Changed table formatting to right-align table columns with numeric data (and pimped the documentation).

Release 1.26 (2015-06-02)

Make table formatting ‘smart’ by having it automatically handle overflow of columns by switching to a different more verbose vertical table layout.

Release 1.25.1 (2015-06-02)

  • Bug fix for a somewhat obscure UnicodeDecodeError in on Python 3.
  • Travis CI now also runs the test suite on PyPy.
  • Documented PyPy compatibility.

Release 1.25 (2015-05-27)

Added the humanfriendly.terminal.usage() function for nice rendering of usage messages on interactive terminals (try humanfriendly --help to see it in action).

Release 1.24 (2015-05-27)

Added the humanfriendly.terminal module with support for ANSI escape sequences, detecting interactive terinals, finding the terminal size, etc.

Release 1.23.1 (2015-05-26)

Bug fix for Python 3 compatibility in format_table().

Release 1.23 (2015-05-26)

Added format_table() function to format tabular data in simple textual tables.

Release 1.22 (2015-05-26)

Added additional string formatting functions compact(), dedent(), format(), is_empty_line() and trim_empty_lines().

Release 1.21 (2015-05-25)

Added support for formatting numbers with thousands separators.

Release 1.20 (2015-05-25)

  • Added a simple command line interface.
  • Added trove classifiers to

Release 1.19 (2015-05-23)

Made it possible to use spinners as context managers.

Release 1.18 (2015-05-23)

Added a Spinner.sleep() method.

Release 1.17 (2015-05-23)

  • Improved interaction between spinner & verbose log outputs: The spinner until now didn’t end each string of output with a carriage return because then the text cursor would jump to the start of the screen line and disturb the spinner, however verbose log output and the spinner don’t interact well because of this, so I’ve decided to hide the text cursor while the spinner is active.
  • Added another example to the documentation of parse_date().

Release 1.16 (2015-03-29)

  • Change spinners to use the ‘Erase in Line’ ANSI escape code to properly clear screen lines.
  • Improve performance of Travis CI and increase multiprocessing test coverage.

Release 1.15 (2015-03-17)

  • Added support for AutomaticSpinner that animates without requiring step() calls.
  • Changed the Python package layout so that all *.py files are in one directory.
  • Added tests for parse_path() and Timer.rounded.

Release 1.14 (2014-11-22)

  • Changed coerce_boolean() to coerce empty strings to False.
  • Added parse_path() function (a simple combination of standard library functions that I’ve repeated numerous times).

Release 1.13 (2014-11-16)

Added support for spinners with an embedded timer.

Release 1.12 (2014-11-16)

Added support for rounded timestamps.

Release 1.11 (2014-11-15)

Added coerce_boolean() function.

Release 1.10 (2014-11-15)

Improved pluralize() by making it handle the simple case of pluralizing by adding ‘s’.

Release 1.9.6 (2014-09-14)

Improved the documentation by adding a few docstring examples via pull request #3.

Release 1.9.5 (2014-06-29)

Improved the test suite by making the timing related tests less sensitive to slow test execution. See but the same thing can happen anywhere. When looked at from that perspective the fix I’m committing here really isn’t a fix, but I suspect it will be fine :-).

Release 1.9.4 (2014-06-29)

Release 1.9.3 (2014-06-29)

  • Automatically disable Spinner when stream.isatty() returns False.
  • Improve the makefile by adding install and coverage targets.
  • Remove the makefile generated by Sphinx (all we need from it is one command).
  • Add unit tests for prompt_for_choice() bringing coverage back up to 95%.

Release 1.9.2 (2014-06-29)

Added support for ‘B’ bytes unit to parse_size() via pull request #2.

Release 1.9.1 (2014-06-23)

Improved the prompt_for_choice() function by clearly presenting the default choice (if any).

Release 1.9 (2014-06-23)

Added the prompt_for_choice() function.

Release 1.8.6 (2014-06-08)

Enable Spinner to show progress counter (percentage).

Release 1.8.5 (2014-06-08)

Make Timer objects “resumable”.

Release 1.8.4 (2014-06-07)

Make the Spinner(label=...) argument optional.

Release 1.8.3 (2014-06-07)

Make it possible to override the label for individual steps of spinners.

Release 1.8.2 (2014-06-01)

Automatically rate limit Spinner instances.

Release 1.8.1 (2014-05-11)

  • Improve Python 3 compatibility: Make sure sequences passed to concatenate() are lists.
  • Submit test coverage from Travis CI to
  • Increase test coverage of concatenate(), Spinner() and Timer().
  • Use assertRaises() instead of try, except and isinstance() in test suite.

Release 1.8 (2014-05-10)

  • Added support for Python 3 thanks to a pull request.
  • Document the supported Python versions (2.6, 2.7 and 3.4).
  • Started using Travis CI to automatically run the test suite.

Release 1.7.1 (2013-09-22)

Bug fix for concatenate() when given only one item.

Release 1.7 (2013-09-22)

Added functions concatenate() and pluralize(), both originally developed in private scripts.

Release 1.6.1 (2013-09-22)

Bug fix: Don’t raise an error in format_path() if $HOME isn’t set.

Release 1.6 (2013-08-12)

Added a Spinner class that I originally developed for pip-accel.

Release 1.5 (2013-07-07)

Added a Timer class to easily keep track of long running operations.

Release 1.4.3 (2013-07-06)

Fixed various edge cases in format_path(), making it more robust.

Release 1.4.2 (2013-06-27)

Improved the project description in and added a link to online documentation on PyPI.

Release 1.4.1 (2013-06-27)

Renamed the package from human-friendly to humanfriendly.

Release 1.4 (2013-06-17)

Added the parse_date() function.

Release 1.3.1 (2013-06-17)

  • Improved the documentation by adding lots of examples.
  • Renamed the arguments to the format_size() and format_timespan() functions.

Release 1.3 (2013-06-17)

Added the format_timespan() function.

Release 1.2 (2013-06-17)

Started using Sphinx to generate API documentation from docstrings.

Release 1.1 (2013-06-17)

Added the format_path() function.

Release 1.0 (2013-06-17)

The initial commit of the project, created by gathering functions from various personal scripts that I wrote over the past years.