Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to check for existence of a metadata plugin tag in item_fields section of the inline plugin ? #2406

Closed
euri10 opened this issue Jan 22, 2017 · 4 comments

Comments

Projects
None yet
2 participants
@euri10
Copy link
Contributor

commented Jan 22, 2017

Problem

I want to use acousticbrains tags, tonal in particular, in a custom format with the inline plugin, but I fail at checking if the tag exists.

So when the tonal field exists it's ok:

➜  ~ beet ls wisemen
01/15--Wisemen Approaching---Wisemen-----Introducing (No Matt--Rap-------
-------124 bpm-- --0.946985244751--

now issue is when it doesn't

➜  ~ beet ls wise
Traceback (most recent call last):
  File "/usr/local/bin/beet", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/__init__.py", line 1209, in main
    _raw_main(args)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/__init__.py", line 1196, in _raw_main
    subcommand.func(lib, suboptions, subargs)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/commands.py", line 1071, in list_func
    list_items(lib, decargs(args), opts.album)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/commands.py", line 1067, in list_items
    ui.print_(format(item, fmt))
  File "/usr/local/lib/python2.7/dist-packages/beets/library.py", line 341, in __format__
    return self.evaluate_template(spec)
  File "/usr/local/lib/python2.7/dist-packages/beets/dbcore/db.py", line 464, in evaluate_template
    self._template_funcs())
  File "/usr/local/lib/python2.7/dist-packages/beets/util/functemplate.py", line 574, in substitute
    res = self.interpret(values, functions)
  File "/usr/local/lib/python2.7/dist-packages/beets/util/functemplate.py", line 566, in interpret
    return self.expr.evaluate(Environment(values, functions))
  File "/usr/local/lib/python2.7/dist-packages/beets/util/functemplate.py", line 274, in evaluate
    out.append(part.evaluate(env))
  File "/usr/local/lib/python2.7/dist-packages/beets/util/functemplate.py", line 176, in evaluate
    if self.ident in env.values:
  File "/usr/lib/python2.7/_abcoll.py", line 388, in __contains__
    self[key]
  File "/usr/local/lib/python2.7/dist-packages/beets/library.py", line 382, in __getitem__
    value = self._get(key)
  File "/usr/local/lib/python2.7/dist-packages/beets/library.py", line 373, in _get
    return self._get_formatted(self.model, key)
  File "/usr/local/lib/python2.7/dist-packages/beets/dbcore/db.py", line 69, in _get_formatted
    value = model._type(key).format(model.get(key))
  File "/usr/local/lib/python2.7/dist-packages/beets/dbcore/db.py", line 305, in get
    return self[key]
  File "/usr/local/lib/python2.7/dist-packages/beets/dbcore/db.py", line 228, in __getitem__
    return getters[key](self)
  File "/usr/local/lib/python2.7/dist-packages/beetsplug/inline.py", line 114, in _expr_func
    raise InlineError(python_code, exc)
beetsplug.inline.InlineError: error in inline path field code:
u'--{}--'.format(tonal)
NameError: name 'tonal' is not defined

I'm aware of the %ifdef{$tonal,$tonal,'no'} that works well in my config snippet below if I put it straight into the format_item (the commented format_item line below)

Now I'd wish to test for that existence in the item_fields: section of the inline plugin to format it to my needs, this is where I fail, any idea if that's possible ?

Setup

  • OS: debian
  • Python version: 2.7.13
  • beets version: 1.4.2
  • Turning off plugins made problem go away (yes/no):

My configuration (output of beet config) is:

format_item: $my_format $my_acousticbrainz
#format_item: $track/$tracktotal - $album - $albumartist - $title - $artist - $genre - [$bpm - %ifdef{$tonal,$tonal,'no'} - $key_str    ength]

item_fields:
my_acousticbrainz: u'--{}--'.format(tonal)
my_format: u'{:02d}/{:02d}--{:-<20.20}--{:-<10.10}--{:-<20.20}--{:-<10.10}\n-------{:3.0f} bpm--'.format(track, tracktotal, album, albumartist, title, genre, bpm)
@sampsyo

This comment has been minimized.

Copy link
Member

commented Jan 22, 2017

The inline plugin sets all the values as Python local variables. So you can use any technique to check whether a given variable name exists in scope, like so: http://stackoverflow.com/questions/843277/how-do-i-check-if-a-variable-exists

@sampsyo sampsyo closed this Jan 22, 2017

@euri10

This comment has been minimized.

Copy link
Contributor Author

commented Jan 22, 2017

well I tried 3 things, none behave like the ifdef

  • my_acousticbrainz that uses the try/except looks fine at first sight, but if a match has been previously found, the variable still exists and is displayed for subsequent ls matches which is wrong, see log below, item 01/19 display a tonal while it has none, it uses the one fron the item 15/15 just above.

  • my_abz_local that checks in locals() fails every time

  • my_abz_global has the same behaviour as the try / except,

should the variable be de-registered somewhat or is it something I should take care of in my custom item_fields ?

➜  ~ beet ls ennio
......(removed for readability)....


13/15--Once Upon a Time in --Ennio Morr--Friendship and Love---Classical-
-------152 bpm-- 0.983314812183 --0.983314812183-- locals? --0.983314812183--
14/15--Once Upon a Time in --Ennio Morr--Speakeasy-------------Classical-
-------110 bpm-- 0.803279161453 --0.803279161453-- locals? --0.803279161453--
15/15--Once Upon a Time in --Ennio Morr--Deborah's Theme / Am--Classical-
-------136 bpm-- 0.952246785164 --0.952246785164-- locals? --0.952246785164--

......(the next item has no tonal yet shows the one of the previous item found)....

01/19--Yo-Yo Ma Plays Ennio--Yo-Yo Ma /--Gabriel's Oboe------------------
-------  0 bpm-- 'no' --0.952246785164-- locals? --0.952246785164--
02/19--Yo-Yo Ma Plays Ennio--Yo-Yo Ma /--The Falls-----------------------
-------  0 bpm-- 'no' --0.952246785164-- locals? --0.952246785164--

......(removed for readability)....
format_item: $my_format %ifdef{tonal,$tonal,'no'} $my_acousticbrainz $my_abz_local $my_abz_global
item_fields:
    my_acousticbrainz: |
        try:
            return u'--{}--'.format(tonal)
        except NameError:
            return u'exception'
    my_abz_local: |
        if 'tonal' in locals():
            return u'--{}--'.format(tonal)
        else:
            return u'locals?'
    my_abz_global: |
        if 'tonal' in globals():
            return u'--{}--'.format(tonal)
        else:
            return u'globals?'
    my_format: u'{:02d}/{:02d}--{:-<20.20}--{:-<10.10}--{:-<20.20}--{:-<10.10}\n-------{:3.0f} bpm--'.format(track, tracktotal, album, albumartist, title, genre, bpm)
@sampsyo

This comment has been minimized.

Copy link
Member

commented Jan 22, 2017

Sorry, I don't understand from that output what's going on here. Maybe you can cook up instructions to reproduce the problem from scratch locally?

@euri10

This comment has been minimized.

Copy link
Contributor Author

commented Jan 23, 2017

I'm aware of the %ifdef that I could use it in the format_item to check for existence of tonal metatag, but I'm not able that way to craft more formatting on it, so I need to somewhat replicate the ifdef behaviour in a custom format in item_fields:

Given that, the following format item displays the tonal with the ifdef and each of the 3 subsequent custom formats I wrote ($my_acousticbrainz $my_abz_local $my_abz_global) is an attempt to "replicate" ifdef using python code in the spirit of your comment

So you can use any technique to check whether a given variable name exists in scope

The correct custom format output should be "equal" to the ifdef output

format_item: $track/$tracktotal $album - $albumartist %ifdef{tonal,$tonal,'no'} $my_acousticbrainz $my_abz_local     $my_abz_global
item_fields:
    my_acousticbrainz: |
        try:
            tonal
        except NameError:
            return u'exception'
        else:
            return u'--{}--'.format(tonal)
    my_abz_local: |
        if 'tonal' in locals():
            return u'--{}--'.format(tonal)
        else:
            return u'no locals'
    my_abz_global: |
        if 'tonal' in globals():
            return u'--{}--'.format(tonal)
        else:
            return u'no globals'

Now I have 2 Ennio Morricone albums, one has the tonal infos for its tracks, the other has none.

The output is the following

➜  ~ beet ls ennio
05/15 Once Upon a Time in America - Ennio Morricone 0.491696238518 --0.491696238518-- no locals --0.491696238518--
09/15 Once Upon a Time in America - Ennio Morricone 0.75162178278 --0.75162178278-- no locals --0.75162178278--
01/15 Once Upon a Time in America - Ennio Morricone 0.850122451782 --0.850122451782-- no locals --0.850122451782--
02/15 Once Upon a Time in America - Ennio Morricone 0.787155330181 --0.787155330181-- no locals --0.787155330181--
03/15 Once Upon a Time in America - Ennio Morricone 0.712361097336 --0.712361097336-- no locals --0.712361097336--
04/15 Once Upon a Time in America - Ennio Morricone 0.0836338177323 --0.0836338177323-- no locals --0.0836338177323--
06/15 Once Upon a Time in America - Ennio Morricone 0.67206466198 --0.67206466198-- no locals --0.67206466198--
07/15 Once Upon a Time in America - Ennio Morricone 0.126243561506 --0.126243561506-- no locals --0.126243561506--
08/15 Once Upon a Time in America - Ennio Morricone 0.364285051823 --0.364285051823-- no locals --0.364285051823--
10/15 Once Upon a Time in America - Ennio Morricone 0.217891916633 --0.217891916633-- no locals --0.217891916633--
11/15 Once Upon a Time in America - Ennio Morricone 0.0587243363261 --0.0587243363261-- no locals --0.0587243363261--
12/15 Once Upon a Time in America - Ennio Morricone 0.933286130428 --0.933286130428-- no locals --0.933286130428--
13/15 Once Upon a Time in America - Ennio Morricone 0.983314812183 --0.983314812183-- no locals --0.983314812183--
14/15 Once Upon a Time in America - Ennio Morricone 0.803279161453 --0.803279161453-- no locals --0.803279161453--
15/15 Once Upon a Time in America - Ennio Morricone 0.952246785164 --0.952246785164-- no locals --0.952246785164--
01/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
02/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
03/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
04/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
05/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
06/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
07/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
08/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
09/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
10/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
11/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
12/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
13/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
14/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
15/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
16/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
17/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
18/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--
19/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--

Looking at that output :

  • ifdef behaves correctly, returns the tonal for the tracks of the album where it exists, no otherwise.

  • my_abz_local custom format returns no_locals everytime, so no tonal never seem to exist in locals()

  • my_abz_global and my_acousticbrainz behave the same, it looks it's correct at first sight because for the 1st album it returns the tonal correctly, but for the 2nd album which has no tonal, it outputs the tonal of the last track found in the preceding album, said differently if you look only at those 2 lines

15/15 Once Upon a Time in America - Ennio Morricone 0.952246785164 --0.952246785164-- no locals --0.952246785164--
01/19 Yo-Yo Ma Plays Ennio Morricone - Yo-Yo Ma / Ennio Morricone / Roma Sinfonietta 'no' --0.952246785164-- no locals --0.952246785164--

the 0.952246785164 tonal output for the 2nd line is incorrect as no tonal exists for that track, it's the one from the preceeding line.

Is it an expected behaviour ?

sampsyo added a commit that referenced this issue Jun 1, 2019

inline: Fix a ridiculously subtle flexattr bug
As detailed here:
#2406 (comment)

In a *function-style* definition, we didn't properly *un-define* the
values for a given item after each function invocation. So when a field
wasn't defined, it would get the value for the previously-formatted
object instead. It now properly throws a NameError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.