Skip to content

Commit 06eac79

Browse files
committed
Centralize requests setup with requests.Session
Improve requests performance with requests.Session which uses connection pooling for repeated requests to the same host. Additionally, this centralizes request configuration, making sure that we use the same timeout and provide beets user agent for all requests.
1 parent c40db10 commit 06eac79

File tree

2 files changed

+28
-44
lines changed

2 files changed

+28
-44
lines changed

beetsplug/lyrics.py

+26-42
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from __future__ import annotations
1818

19+
import atexit
1920
import errno
2021
import itertools
2122
import json
@@ -24,13 +25,12 @@
2425
import re
2526
import struct
2627
import unicodedata
27-
import warnings
2828
from contextlib import suppress
2929
from dataclasses import dataclass
3030
from functools import cached_property, partial, total_ordering
3131
from http import HTTPStatus
3232
from typing import TYPE_CHECKING, ClassVar, Iterable, Iterator
33-
from urllib.parse import quote, urlencode, urlparse
33+
from urllib.parse import quote, urlparse
3434

3535
import requests
3636
from typing_extensions import TypedDict
@@ -106,6 +106,22 @@ class NotFoundError(requests.exceptions.HTTPError):
106106
pass
107107

108108

109+
class TimeoutSession(requests.Session):
110+
def request(self, *args, **kwargs):
111+
kwargs.setdefault("timeout", 10)
112+
return super().request(*args, **kwargs)
113+
114+
115+
r_session = TimeoutSession()
116+
r_session.headers.update({"User-Agent": USER_AGENT})
117+
118+
119+
@atexit.register
120+
def close_session():
121+
"""Close the requests session on shut down."""
122+
r_session.close()
123+
124+
109125
# Utilities.
110126

111127

@@ -246,21 +262,7 @@ def fetch_url(self, url, **kwargs):
246262
is unreachable.
247263
"""
248264
try:
249-
# Disable the InsecureRequestWarning that comes from using
250-
# `verify=false`.
251-
# https://github.com/kennethreitz/requests/issues/2214
252-
# We're not overly worried about the NSA MITMing our lyrics scraper
253-
with warnings.catch_warnings():
254-
warnings.simplefilter("ignore")
255-
r = requests.get(
256-
url,
257-
verify=False,
258-
headers={
259-
"User-Agent": USER_AGENT,
260-
},
261-
timeout=10,
262-
**kwargs,
263-
)
265+
r = r_session.get(url)
264266
except requests.RequestException as exc:
265267
self._log.debug("lyrics request failed: {0}", exc)
266268
return
@@ -368,9 +370,7 @@ def warn(self, message: str, *args) -> None:
368370

369371
def fetch_json(self, *args, **kwargs):
370372
"""Wrap the request method to raise an exception on HTTP errors."""
371-
kwargs.setdefault("timeout", 10)
372-
kwargs.setdefault("headers", {"User-Agent": USER_AGENT})
373-
r = requests.get(*args, **kwargs)
373+
r = r_session.get(*args, **kwargs)
374374
if r.status_code == HTTPStatus.NOT_FOUND:
375375
raise NotFoundError("HTTP Error: Not Found", response=r)
376376
r.raise_for_status()
@@ -535,10 +535,7 @@ class Genius(SearchBackend):
535535
def __init__(self, config, log):
536536
super().__init__(config, log)
537537
self.api_key = config["genius_api_key"].as_str()
538-
self.headers = {
539-
"Authorization": "Bearer %s" % self.api_key,
540-
"User-Agent": USER_AGENT,
541-
}
538+
self.headers = {"Authorization": f"Bearer {self.api_key}"}
542539

543540
def fetch(self, artist: str, title: str, *_) -> str | None:
544541
"""Fetch lyrics from genius.com
@@ -573,18 +570,13 @@ def _search(self, artist, title):
573570
search_url = self.base_url + "/search"
574571
data = {"q": title + " " + artist.lower()}
575572
try:
576-
response = requests.get(
577-
search_url,
578-
params=data,
579-
headers=self.headers,
580-
timeout=10,
581-
)
573+
r = r_session.get(search_url, params=data, headers=self.headers)
582574
except requests.RequestException as exc:
583575
self._log.debug("Genius API request failed: {0}", exc)
584576
return None
585577

586578
try:
587-
return response.json()
579+
return r.json()
588580
except ValueError:
589581
return None
590582

@@ -979,13 +971,7 @@ def get_bing_access_token(self):
979971
}
980972

981973
oauth_url = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13"
982-
oauth_token = json.loads(
983-
requests.post(
984-
oauth_url,
985-
data=urlencode(params),
986-
timeout=10,
987-
).content
988-
)
974+
oauth_token = r_session.post(oauth_url, params=params).json()
989975
if "access_token" in oauth_token:
990976
return "Bearer " + oauth_token["access_token"]
991977
else:
@@ -1202,10 +1188,8 @@ def append_translation(self, text, to_lang):
12021188
"https://api.microsofttranslator.com/v2/Http.svc/"
12031189
"Translate?text=%s&to=%s" % ("|".join(text_lines), to_lang)
12041190
)
1205-
r = requests.get(
1206-
url,
1207-
headers={"Authorization ": self.bing_auth_token},
1208-
timeout=10,
1191+
r = r_session.get(
1192+
url, headers={"Authorization": self.bing_auth_token}
12091193
)
12101194
if r.status_code != 200:
12111195
self._log.debug(

setup.cfg

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ omit = beets/test/*
2121
precision = 2
2222
skip_empty = true
2323
show_missing = true
24-
exclude_lines =
25-
pragma: no cover
24+
exclude_also =
25+
@atexit.register
2626
if TYPE_CHECKING
2727
if typing.TYPE_CHECKING
2828
raise AssertionError

0 commit comments

Comments
 (0)