Time to rethink path formats?

The path formats feature is great for basic use, but it gets messy quickly. I want my music library organized just-so, and the way I do that in beets is cumbersome. Maybe it’s my Python bias speaking, but I think a pure Python solution would be easier to follow than a translation layer between text and the underlying Python.

In my config, I define a fake comment and fake tab using regex, that allows cleaner line breaks that line up with the surrounding lines.

Then I spin a tangled web of if-elses, which are hard to understand. Without line breaks, it’s impossible.

Granted, nobody but me does fake comments. Can people with advanced path formats share their configs? Do you create them in your YAML, or do you have to conceptualize them elsewhere because the if-else chains are too messy and there are no comments?

Should I put all the logic into inline's album_fields and item_fields? The complicated functions go there but my base logic is still in the normal path formatter. Are template functions available when using inline?

Interesting! I’d be interested to hear how others tackle this sort of thing too. It is perhaps worth exploring the “all-inline” approach to see how far it can take you.

I don’t think it’s currently possible to call template functions from within inline expressions, but that would be a cool thing to add to support this sort of use case!

Ah, I had forgotten we had recently discussed this possibility and found a tricky way to do it:

Kinda off-topic, but sometimes I wished that the path: entries were Jinja2 templates. But that could open another can of worms

1 Like

I tested it and feel good. Need to do more tests. I have a few hundred imports coming eventually™ and it should be a good chance to torture test this concept. After this initial test, I feel better about Python/some other system and worse about the current setup. However, forcing users to do it manually is a no-go, if my experience is an indication.

pros

  • incredibly readable: I can set up my paths like a regular python script and loosely follow PEP8
  • Python engineering is available. I can autoformat, peek function definitions in VS code, etc.
  • comments and line breaks are VIPs and don’t need regex hacks
  • possible to write a script to convert from existing path format to Python???
  • conservatively, 2x faster than my old system. see below.

cons / notes

  • took 4ish hours. including some non-mandatory light re-engineering, but also stuff like remapping $myfunc{album} to myfunc(album) in the definition and the function call.
  • confusing importing my own plugins (could be my sloppy, ancient dev environment)
  • how do i import base beets path functions (aunique)?
  • repeated string appends (s += albumartist): this is probably where a dedicated template language thrives
  • sequential line breaks are not allowed in the “: |” format I was using; so no space between functions etc.
  • VS code doesn’t know anything about beets vars (items, album, albumtype, etc.). it underlines all these variables in red because this would be invalid python. get around this by importing something from beets? (The “# Item fields.” and “album fields” sections of inline.py look promising.)
  • syntax highlight breaks when i actually paste it into config.yaml (everything is highlighted as a long string). get around this by dumping everything in a Python/beets plugin and just calling that with inline? Update: Getting the imports working with beet fields like album is non trivial, at least for me.
  • pdb.set_trace + dir() doesn’t show anything for item fields? (works perfect for album fields). all the item fields are available but you must know them by name (ex. mb_releasetrackid).
  • Is there anything that base Python3 handles worse than the beets path formatter? Unicode? Case sensitivity? Dupe handling I think happens one layer above, after the path is already set.
  • exceptions / parse errors don’t indicate where the error occured. The error mentions “line 70”, so the error output could just be improved to visually show where errors are. (Something to improve in inline)
  • only tested on windows
  • mixing album / item fields is annoying. I have to call 4 functions: album1, item1, album2, item2, because of how I set up the field order. (I want media in the folder name, even though it’s item-level).
  • The / path separator is interpreted as a regular /, so subfolder creation is broken if you do it within Inline.

Performance

i’ve moved all my album fields to a single python inline call. is there something about inline that might cause poor performance invoking 10ish functions? 8ish of them are very basic 5 line string manipulation functions. is compile_inline the culprit? Edit: Or maybe commenting out aunique does it? Or the regex in the path formats?

Comparison

Here’s what I have now. I rewrote the item functions and everything seems to work on 2 album moves. The Python version is a tiny bit bigger, but much more readable. The length isn’t directly comparable anyway. Like I said, I changed the code a bit as part of the conversion.