Inconsistency in relative path handling in the config

I’ve noticed that handling of relative paths in config.yaml is inconsistent, which makes it difficult to have a self contained library and beets configuration. It’d be nice if either this was consistent, or if we could use some form of templating scheme, i.e. string.format or string.Template, to access the most common paths. It could be worthwhile to provide a new type when plugins interact with the config to handle this transparently for their options as well, giving them an absolute path.

From what I’ve seen (where BEETSDIR is the path where config.yaml lives):

  • directory: relative to BEETSDIR
  • library: relative to BEETSDIR
  • pluginpath: relative to PWD
  • importfeeds: m3u: relative to directory
  • importfeeds: m3u_multi: relative to BEETSDIR
  • alternatives: relative to directory

Any thoughts on the cleanest way to address this? I was going to start working on a pull request, but would like to determine the correct approach.


1 Like

Good catches! For what it’s worth, Confuse (our configuration library) provides built-in functionality that defaults to "relative to BEETSDIR". That’s the as_filename method—like this, for example.

Other config options that use as_str or just plain get should probably be changed to use as_filename.

Ah, great, thanks. That’s simple enough. pluginpath currently uses as_str_seq(), guessing we can just do [p.as_filename() for p in config[‘pluginpath’]] or so, instead?

Well, that one might be a bit more complicated. The as_str_seq thing is a bit more powerful—it can take a single string and split it on whitespace. Maybe we should leave that one alone for a little bit while we take a look at the others, which are hopefully easier?

I found this topic specifically because of pluginpath :sweat_smile:

I created the following (really hacky) patch which makes it “work” although it’s real bad and as far as I can tell should really be implemented as a new Template type in Confuse (something that combines StrSeq with Filename)?

(I was going to try my hand at creating such a thing, but very, very quickly got way out of my depth. :innocent:)

diff --git a/beets/ui/ b/beets/ui/
index 8d980d54..0ebe9f68 100644
--- a/beets/ui/
+++ b/beets/ui/
@@ -1114,6 +1116,7 @@ def _load_plugins(options, config):
     """Load the plugins specified on the command line or in the configuration.
     paths = config['pluginpath'].as_str_seq(split=False)
+    paths = [confuse.Filename(default=p).value(config['lolnopeleethax']) for p in paths]
     paths = [util.normpath(p) for p in paths]
     log.debug(u'plugin paths: {0}', util.displayable_path(paths))

Edit: scratch that, this patch doesn’t even work :joy: :innocent: