beetbox / beetbox/beets

zero plugin causes infinite recursion error

Open
#5,523 0 comments 0 reactions 0 assignees View on GitHub
zero
Dominant language
Python
Stars
15.7k
Forks
2.1k
Avg merge
4d 21h
Merged PRs (30d)
31

Description

enabling the `zero` plugin causes an infinite recursion error for (i think) all tag modification commands.

### Problem

Running this command in verbose (`-vv`) mode:

```sh
$beet -vv modify geith alive title="alive"
```

Led to this problem:

```
user configuration: /home/keltoj/.config/beets/config.yaml
data directory: /home/keltoj/.config/beets
plugin paths:
inline: adding item field art
inline: adding item field alb
inline: adding item field tit
inline: adding item field yr
Sending event: pluginload
library database: /home/keltoj/.config/beets/library.db
library directory: /home/keltoj/music
Sending event: library_opened
Parsed query: AndQuery([AnyFieldQuery('geith', ('artist', 'title', 'comments', 'album', 'albumartist', 'genre'), SubstringQuery), AnyFieldQuery('alive', ('artist', 'title', 'comments', 'album', 'albumartist', 'genre'), SubstringQuery)])
Parsed sort: NullSort()
Modifying 1 items.
chris geith - invisible reality - 03 - alive
title: 03 - alive -> alive
Really modify, move and write tags? (Yes/no/select) yes

Sending event: write
zero: composer: -> None
zero: arranger: -> None
zero: isrc: -> None
zero: lyrics: -> None
zero: mb_trackid: -> None
zero: art: -> None
zero: comments: -> None
zero: original_year: 0 -> None
zero: tracktotal: 0 -> None
zero: images: -> None
Sending event: after_write
moving /home/keltoj/music/chris_geith/2021_invisible_reality/03_03_-_alive.mp3 to synchronize path
Parsed query: AndQuery([NoneQuery('album_id', True)])
Parsed sort: NullSort()
Parsed query: AndQuery([BooleanQuery('comp', 1, fast=True)])
Parsed sort: NullSort()
Traceback (most recent call last):
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/util/functemplate.py", line 563, in substitute
res = self.compiled(values, functions)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/util/functemplate.py", line 587, in wrapper_func
args[VARIABLE_PREFIX + varname] = values[varname]
~~~~~~^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/library.py", line 483, in __getitem__
value = self._get(key)
^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/library.py", line 471, in _get
return self._get_formatted(self.model, key)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 134, in _get_formatted
value = model._type(key).format(model.get(key))
^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/library.py", line 739, in get
return self._get(key, default, raise_=with_album)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 433, in _get
return getters[key](self)
^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beetsplug/inline.py", line 109, in _expr_func
values = _dict_for(obj)
^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beetsplug/inline.py", line 101, in _dict_for
out = dict(obj)
^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/library.py", line 702, in __getitem__
return super().__getitem__(key)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 452, in __getitem__
return self._get(key, raise_=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 433, in _get
return getters[key](self)
^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beetsplug/inline.py", line 109, in _expr_func
values = _dict_for(obj)
^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beetsplug/inline.py", line 101, in _dict_for

#
# etc over and over
#

out = dict(obj)
^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/library.py", line 702, in __getitem__
return super().__getitem__(key)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 452, in __getitem__
return self._get(key, raise_=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 433, in _get
return getters[key](self)
^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beetsplug/inline.py", line 109, in _expr_func
values = _dict_for(obj)
^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beetsplug/inline.py", line 101, in _dict_for
out = dict(obj)
^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/library.py", line 726, in keys
if with_album and self._cached_album:
^^^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/library.py", line 656, in _cached_album
self.__album.load()
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 613, in load
db = self._check_db()
^^^^^^^^^^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 396, in _check_db
if need_id and not self.id:
^^^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 541, in __getattr__
return self[key]
~~~~^^^^^
File "/home/keltoj/.pyenv/versions/3.11.1/lib/python3.11/site-packages/beets/dbcore/db.py", line 452, in __getitem__
return self._get(key, raise_=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
RecursionError: maximum recursion depth exceeded
```

Here's a link to the music files that trigger the bug (if relevant):

### Setup

* OS: Pop!_OS 22.04 LTS
* Python version: 3.11.1
* beets version: 2.0.0
* Turning off plugins made problem go away (yes/no): yes (disabling zero)

My configuration (output of `beet config`) is:

```yaml
plugins: inline duplicates edit info zero
asciify_paths: yes
item_fields:
art: artist.replace(" ", "_")
alb: album.replace(" ", "_")
tit: title.replace(" ", "_")
yr: year if year else "0000"
duplicates:
move: ~/dupes/
keys: [title, album]
edit:
itemfields: acoustid_fingerprint acoustid_id added alb album album_id albumartist albumartist_credit albumartist_sort albumartists albumartists_credit albumartists_sort albumdisambig albumstatus albumtype albumtypes arranger art artist artist_credit artist_sort artists artists_credit artists_ids artists_sort asin barcode bitdepth bitrate bitrate_mode bpm catalognum channels comments comp composer composer_sort country day disc discogs_albumid discogs_artistid discogs_labelid disctitle disctotal encoder encoder_info encoder_settings filesize format genre grouping id initial_key isrc label language length lyricist lyrics mb_albumartistid mb_albumartistids mb_albumid mb_artistid mb_artistids mb_releasegroupid mb_releasetrackid mb_trackid mb_workid media month mtime original_day original_month original_year path r128_album_gain r128_track_gain release_group_title releasegroupdisambig remixer rg_album_gain rg_album_peak rg_track_gain rg_track_peak samplerate script singleton style tit title track trackdisambig tracktotal work work_disambig year yr
albumfields: added album albumartist albumartist_credit albumartist_sort albumartists albumartists_credit albumartists_sort albumdisambig albumstatus albumtotal albumtype albumtypes artpath asin barcode catalognum comp country day discogs_albumid discogs_artistid discogs_labelid disctotal genre id label language mb_albumartistid mb_albumid mb_releasegroupid month original_day original_month original_year path r128_album_gain release_group_title releasegroupdisambig rg_album_gain rg_album_peak script style year
import:
move: yes
autotag: no
directory: ~/music/
paths:
default: %lower{$art/${yr}_$alb/${track}_$tit}
singleton: %lower{$art/singles/$tit}
comp: %lower{compilations/${yr}_$album/${track}_$tit}
zero:
auto: yes
fields: composer arranger isrc lyrics mb_trackid art comments original_year tracktotal images
update_database: true
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the failure with `beet -vv modify geith alive title="alive"` using the configuration shown, then trace the repeated calls through `beetsplug/inline.py`, `beets/library.py`, and `beets/dbcore/db.py`. Done means tag modification no longer reaches a recursion error when the `zero` plugin is enabled, while the reported fields are still handled correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.