Beets has been in beta forever—for small values of forever, at least. I made the first commit to the original Subversion repository (for shame!) on May 14, 2008 and uploaded version 1.0b1 on June 17, 2010. I’m now working on beets’ sixteenth beta. It’s high time that the project hit the big 1.0. I’m excited to give beets the point-zero stamp of approval, but I have two big, backwards-incompatible changes I want to make before sprouting a stable maintenance branch. In this post, I’ll describe my plans for beets 1.0b16 and b17—and beyond.

Beta 16

As nerd-oriented software, beets has a lot of configuration options. The config file, affectionately known as ~/.beetsconfig, has used an INI-like syntax as defined by Python’s ConfigParser since the beginning. More than two years later, beets has outgrown the dated, inflexible ConfigParser system. So the next beta of beets will focus on ripping out ConfigParser altogether and replacing it with an entirely new configuration system that solves many problems at once. Here’s what you can expect in 1.0b16:

  • YAML syntax. The config file has grown a troubling number of half-working syntax hacks over the years. Lists of things have to be separated by whitespace, which means you can’t use spaces in regular expressions. Egregiously, I had to force users to substitute _ characters for :s in query-based path format keys because ConfigParser splits on colons. Because it has a well-defined and nuanced syntax specification, YAML-based config files will eschew these hacks: lists will look like lists and all characters will be treated as equals.
  • You’ll have a ~/.config/beets directory (or the equivalent on Windows). No more cluttering your home directory with the configuration file, the state file, the library database, and maybe even the import log.
  • ConfigParser does not play nice with Unicode. It’s 2012, folks.
  • You’ll be able to combine multiple configuration files—for example, using a global base configuration with per-location overrides.
  • Most crucially, programming with the ConfigParser API is getting to be a nightmare. Look no further than the monstrous import_files function signature to witness the pain of threading every config option through the UI to the business end of the code. Every time I add a new config option or command-line switch to beet import, I have to touch at least five files to keep the frontend and backend in sync and update the unit tests. And that’s just to parse the option: the real work for the feature begins after all this. The ConfigParser disaster discourages me from adding new features to beets.

These problems are so basic that I don’t think I’m alone in growing uneasy with ConfigParser. So I’m writing a new configuration library called Confit (that’s pronounced con-FEE). I hope to make Confit into the best available library for configuring Python applications. I’ll have more to say about Confit on this blog as work progresses.

Beta 17

Unlike b16’s configuration overhaul, beta 17’s nightmare is a less user-visible one: the plugin API. If you browse through the code for beets’ standard plugins, you’ll quickly see that they all employ a tragic conflation between module-scoped and object-scoped variables. There are globals all over the place and a nonsensical distinction between decorated functions and specially-named methods.

The plugin API overhaul will consolidate everything into the object scope. Plugins will follow the singleton pattern, so it will no longer be necessary to keep anything module-global or assigned to the class itself. Decorators will be deemphasized; events will use a method naming convention instead.

And, finally, we’ll drop namespace packages. I didn’t know this when I first started using the beetsplug namespace package for beets plugins, but a bug in distribute utterly breaks them when they’re installed with a program like pip. This meant that some users could never use third-party plugins without reinstalling beets. (PEP 420 fixes everything but, alas, won’t be backported to Python 2.x.)

While these changes aren’t particularly exciting for end users, it’s important that I break all the plugins before 1.0 rather than after. The goal is to make beets’ plugin system future-proof—to contain the spaghetti before it spreads.


With these two major changes out of the way, it will be time for some release candidates and then a massive party as we release 1.0. At this point, I plan on dividing beets development into a stable/trunk development model: version 1.0 will see bug-fix-only releases while the new features go into a separate 1.1 branch. This will let me—and maybe other developers?—experiment with new stuff without rocking the boat for users who don’t want to be bothered.

I have some exciting plans for new directions post-1.0. But, for now, I have two big betas to work on—we can talk about 1.1 and beyond a little later. Keep that dial right here.

Fork me on GitHub