Where to define common functions for use from inline?

My inline rules are becoming more complex, such that I want to define some functions that I can reuse from multiple album_fields and item_fields code blocks.

I suppose I could create a new Python module and import that to use it, but it would be nice to put the functions inside the config.yaml, rather than keeping them external. Is it possible? If not, would it make sense to enhance the inline plugin to allow this?

If you’re at that point, maybe it’s time for a Python module or a Beets plugin. That might be too much feature creep for inline.

You can write a plain ol’ Python module and install it—it should then be importable by any Python code, including inline snippets.

Thanks for the replies!

OK, I’m proceeding with that approach. It’s a little awkward to pass the variables to the module, since they don’t persist across module boundaries AFAICT:

album_fields:
  topdir:    import ctrpaths; return ctrpaths.topdir(globals())
  subdir:    import ctrpaths; return ctrpaths.subdir(globals())
  albumdir:  import ctrpaths; return ctrpaths.albumdir(globals())

item_fields:
  topdir:    import ctrpaths; return ctrpaths.topdir(globals())
  subdir:    import ctrpaths; return ctrpaths.subdir(globals())
  disc_and_track: |
    if disctotal > 9:
      return u'%02i-%02i'% (disc, track)
    elif disctotal > 1:
      return u'%01i-%02i' % (disc, track)
    elif tracktotal > 99:
      return u'%03i' % (track)
    elif tracktotal > 9:
      return u'%02i' % (track)
    else:
      return u'%01i' % (track)

paths:
  singleton: $topdir/%the{$subdir}/%the{$artist} - $title
  comp:      $topdir/%the{$subdir}/$albumdir%aunique{}/($disc_and_track) $artist - $title
  default:   $topdir/%the{$subdir}/$albumdir%aunique{}/($disc_and_track) $title

And then in my ctrpaths module, I do:

def value(key, args):
    return args[key] if key in args else None
...
def topdir(args):
    category = value('category', args)
    return category or 'Artists'

Since category is a flexattr that may not be set.

PR 2988 may also relevant here—I’m using inline primarily to avoid the fact that category flexattr on an album cannot be used in path expressions since it’s not an attribute on the album’s items.

ctrpaths.py
def value(key, args):
    return args[key] if key in args else None

def albumname(args, withartist):
    album = value('album', args)
    albumartist = value('albumartist', args)
    year = value('year', args)

    year_part = f'({year}) ' if year else ''
    artist_part = albumartist + ' - ' if albumartist and withartist else ''
    album_part = album if album else '[Unknown Album]'
    return year_part + artist_part + album_part

def topdir(args):
    category = value('category', args)
    return category or 'Artists'

def subdir(args):
    subcategory = value('subcategory', args)
    if subcategory: return subcategory

    tdir = topdir(args)

    if tdir == 'Classical':
        composer = value('composer', args)
        if not composer: return '[Unknown Composer]'
        if composer.lower() == '[various]': return '[Various Composers]'
        return composer

    if tdir == 'Covers':
        singleton = value('singleton', args)
        if singleton:
            title = value('title', args)
            return title or '[unknown]'
        return '[Various Songs]'

    if tdir == 'Soundtracks':
        franchise = value('franchise', args)
        if not franchise: return '[Unknown Franchise]'
        if franchise.lower() == '[various]': return '[Various Franchises]'
        return franchise

    singleton = value('singleton', args)
    if singleton:
        artist = value('artist', args)
        return artist or '[unknown]'

    comp = value('comp', args)
    if comp: return '[Various Artists]'

    albumartist = value('albumartist', args)
    return albumartist or '[unknown]'

def albumdir(args):
    comp = value('comp', args)
    if comp: return albumname(args, withartist=False)
    return albumname(args, withartist=True)

Please let me know if there’s an easier way to do this.