-
Notifications
You must be signed in to change notification settings - Fork 1.9k
plugins: ensure to log the offending plugin on instantiation failure #5739
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
base: master
Are you sure you want to change the base?
Conversation
Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry. |
3a4a4b7
to
db32fa1
Compare
bde4397
to
2129eb4
Compare
Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry. |
This should be ready to go now; it's easiest to review commit-by-commit. |
2129eb4
to
cc877e5
Compare
minimize how much code is wrapped in a given try...except statement
…roken error handling from a quick test, it appears that the old code shouldn't even be working anymore due to additional quotes in exc.args[0]
also remove a unnecessary check before adding to a set
without an argument (i.e. the default `names=()`), this was a no-op actual plugin loading is triggered by tests, or by the ui code -> Turns out it's not an actual no-op in our testing code due to patching with attaching some side-effects to load_plugins... This is fixed up in the next commit.
Instead of the first call to find_plugins(). This could change behavior slightly, since plugin load (and errors that happen in the process) could occur earlier now. But: - I'd argue this is better anyway, since plugin load errors now happen in the initial call to load_plugins() instead of somewhere in the middle of the first operation that uses plugins. - In our ui code, both happen immediately after each other anyway: ui._setup calls 1) ui._load_plugins -> plugins.load_plugins 2) plugins.types, plugins.named_queries, ...
cc877e5
to
8a862ba
Compare
_classes.add(obj) | ||
|
||
except Exception: | ||
mod = import_module(f".{name}", package=PLUGIN_NAMESPACE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be slightly misleading in some cases, for example:
# beetsplug/discogs.py
...
import beets.ibrary
$ beet import -LI sel
...
** plugin discogs not found
|
||
except Exception: | ||
mod = import_module(f".{name}", package=PLUGIN_NAMESPACE) | ||
except ModuleNotFoundError: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should catch a generic Exception
here? Otherwise every other exception will make beets die, for example:
# beetsplug/discogs.py
...
abc
$ beet import -LI sel
...
Traceback (most recent call last):
File "/home/sarunas/.local/bin/beet", line 5, in <module>
main()
File "/home/sarunas/repo/beets/beets/ui/__init__.py", line 1878, in main
_raw_main(args)
File "/home/sarunas/repo/beets/beets/ui/__init__.py", line 1853, in _raw_main
subcommands, plugins, lib = _setup(options, lib)
File "/home/sarunas/repo/beets/beets/ui/__init__.py", line 1680, in _setup
plugins = _load_plugins(options, config)
File "/home/sarunas/repo/beets/beets/ui/__init__.py", line 1669, in _load_plugins
plugins.load_plugins(plugin_list)
File "/home/sarunas/repo/beets/beets/plugins.py", line 358, in load_plugins
mod = import_module(f".{name}", package=PLUGIN_NAMESPACE)
File "/home/sarunas/.local/share/pyenv/versions/3.9.20/lib/python3.9/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/home/sarunas/repo/beets/beetsplug/discogs.py", line 32, in <module>
abc
NameError: name 'abc' is not defined
and cls != BeetsPlugin | ||
and cls != MetadataSourcePlugin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and cls != BeetsPlugin | |
and cls != MetadataSourcePlugin | |
and cls not in {BeetsPlugin, MetadataSourcePlugin} |
issubclass(cls, BeetsPlugin) | ||
and cls != BeetsPlugin | ||
and cls != MetadataSourcePlugin | ||
and cls not in _instances |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to perform this check? It's unlikely we will come across dupes, and even if we do, classes
is defined as a set, so no dupes are allowed.
if cls in _instances: | ||
return | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt this check is required
if cls in _instances: | |
return |
and cls != MetadataSourcePlugin | ||
and cls not in _instances | ||
): | ||
classes.add(cls) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to store classes in this intermediate set? Can't we just _register_plugin
here?
"""Returns a list of BeetsPlugin subclass instances from all | ||
currently loaded beets plugins. Loads the default plugin set | ||
first. | ||
def find_plugins() -> Iterator[BeetsPlugin]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we returning an iterator here instead of the list?
Came up in #5701 (comment) where an error can't easily be traced back to a plugin.
(Draft because I want to avoid creating merge conflicts for #5701 before that is merged
, and because I might a few additional improvements here.)