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

Improve Deezer error handling #4984

Merged
merged 18 commits into from
Dec 2, 2023
Merged

Improve Deezer error handling #4984

merged 18 commits into from
Dec 2, 2023

Conversation

arsaboo
Copy link
Contributor

@arsaboo arsaboo commented Nov 1, 2023

Description

Fixes #4983

To Do

  • Documentation.
  • Changelog.
  • Tests.

@JOJ0
Copy link
Member

JOJ0 commented Nov 16, 2023

Since I recently work a little with Deezer as my metadata source, I cherry-picked this PR into my personal main-branch. Remind me how that goes in a couple of days/weeks, I'm sure we can merge this then! :-) Thanks for another useful submission @arsaboo 💯

docs/changelog.rst Outdated Show resolved Hide resolved
Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding these additional exception handlers seems great! I might be confused, so please tell me if this cogent make sense, but it seems like we might also want to restore the checking for Deezer-specific API errors?

@@ -75,13 +75,12 @@ def album_for_id(self, album_id):
deezer_id = self._get_id("album", album_id, self.id_regex)
if deezer_id is None:
return None

album_data = requests.get(self.album_url + deezer_id).json()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct me if I’m wrong, but it seems like we lost this layer of error checking. That is, it seems like we should still check for the “error” key in the JSON response?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try-except block should capture it. If there is an error key, it should be caught in except block. It is possible that we may have to capture other exceptions (once we know which ones), but that is easy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm; I don't think I quite see the idea here… what exception will be raised when there is an error key? (Is there some other code that checks for the existence of this key, since it doesn't seem to happen here?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok...I see now what I was missing. I updated the code to handle the error key.

beetsplug/deezer.py Outdated Show resolved Hide resolved
@@ -75,13 +75,12 @@ def album_for_id(self, album_id):
deezer_id = self._get_id("album", album_id, self.id_regex)
if deezer_id is None:
return None

album_data = requests.get(self.album_url + deezer_id).json()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm; I don't think I quite see the idea here… what exception will be raised when there is an error key? (Is there some other code that checks for the existence of this key, since it doesn't seem to happen here?)

@arsaboo
Copy link
Contributor Author

arsaboo commented Nov 22, 2023

fixed the handling of Deezer API errors, i.e., when the response includes error key.

Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Here are a few more comments on the current version.

beetsplug/deezer.py Outdated Show resolved Hide resolved
beetsplug/deezer.py Outdated Show resolved Hide resolved
beetsplug/deezer.py Outdated Show resolved Hide resolved
beetsplug/deezer.py Outdated Show resolved Hide resolved
beetsplug/deezer.py Outdated Show resolved Hide resolved
Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking pretty good, modulo a couple of comments from the previous round that now apply to the consolidated error handling function!

beetsplug/deezer.py Outdated Show resolved Hide resolved
beetsplug/deezer.py Outdated Show resolved Hide resolved
@arsaboo arsaboo closed this Nov 28, 2023
@arsaboo arsaboo reopened this Nov 28, 2023
data = response.json()
except (
requests.ConnectionError,
requests.exceptions.RequestException,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stable and latest docs say both of these exceptions are in requests already: https://requests.readthedocs.io/en/stable/api/#exceptions

does your testing tell you otherwise?

not sure about older versions though, no docs for them online

Copy link
Member

@JOJ0 JOJ0 Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah and now found this older comment, so actually this still applies: #4984 (comment)

Copy link
Member

@JOJ0 JOJ0 Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm @sampsyo didn't you mean the other way round in that comment? If we catch RequestException we'd also catch ConnectionError? And in fact catch each and every exception, since they all inherit from RequestException

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it looks like that should catch all requests exception https://stackoverflow.com/questions/16511337/correct-way-to-try-except-using-python-requests-module

Will make the change tomorrow morning.

Copy link
Member

@JOJ0 JOJ0 Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but hey @arsaboo I wanted to add: Just my thoughts and I don't really know if catching all exceptions requests offers is the perfect idea! Maybe @sampsyo did mean it like he wrote in the first place (ConnectionError catching is enough).

The rule of thumb for catching errors often is: Don't catch everything.

Maybe there are situations where we actually want the importer to crash and tell the beets user that there is a serious problem. If we catch everything then in a normal important run without seeing logs the importer would for example simply fail silently and the user might not even see the reason why they are not getting any results from deezer!!! just think about that and look at this page again, it shows closely which errors derive from which:https://requests.readthedocs.io/en/stable/_modules/requests/exceptions/#ConnectionError

By catching RequestException we would even catch any timeout-related exceptions, including when we get rate-limited! In that case we would just move on siltently ignoring it. But maybe for this case you are planning a subsequent PR for catching timeout stuff, rigfht before the RequestException? (if that's possible to give a preference what's catched first, no expert here, need to read the docs?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Often these are not serious problems....the API errors out or something trivial (and often resolves in the next run). In any case, I will wait for a consensus before making changes.

Also, we are not masking anything....we are telling the user that there was an error. Instead of self._log.debug, we can make it self._log.error so that it is not missed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yeah that's true! making it error-level actually shows it always! yeah good point!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool...updated the PR.

Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonderful! Really nice work getting this all squared away, @arsaboo. This is a clear improvement on the ad hoc nature of the old error handling. A round of applause!! 👏👏👏

@sampsyo sampsyo merged commit dc0d405 into beetbox:master Dec 2, 2023
11 checks passed
@arsaboo arsaboo deleted the deezer_error branch December 3, 2023 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Deezer plugin hangs and errors out instead of gracefully handling timeout errors
3 participants