Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions lidarrmetadata/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
import asyncio

from quart import Quart, abort, make_response, request, jsonify, redirect, url_for
from quart.exceptions import HTTPStatusException
from werkzeug.exceptions import HTTPException

import redis
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
import datetime
from datetime import timedelta
from dateutil import parser
Expand All @@ -17,6 +16,13 @@
import aiohttp
from timeit import default_timer as timer
from spotipy import SpotifyException
# TODO: Needs sentry 1.43
# from sentry_sdk.integrations.asyncio import AsyncioIntegration
# TODO: Needs upgrade of urllib3 to 1.26.11
# from sentry_sdk.integrations.asyncpg import AsyncPgIntegration
# TODO: Needs a different version of quart or you get
# cannot import name '_request_ctx_stack' from 'quart'
# from sentry_sdk.integrations.quart import QuartIntegration
import Levenshtein

import lidarrmetadata
Expand All @@ -43,9 +49,13 @@
processor = util.SentryTtlProcessor(ttl=app.config['SENTRY_TTL'])

sentry_sdk.init(dsn=app.config['SENTRY_DSN'],
integrations=[FlaskIntegration()],
release=f"lidarr-metadata-{lidarrmetadata.__version__}",
before_send=processor.create_event,
integrations=[
],
# TODO: Needs later sentry
# enable_tracing=True,
traces_sample_rate=1.0,
send_default_pii=True)

# Allow all endpoints to be cached by default
Expand Down Expand Up @@ -101,7 +111,7 @@ def handle_error(e):
sentry_sdk.capture_exception(e)
return jsonify(error='Internal server error'), 500

@app.errorhandler(HTTPStatusException)
@app.errorhandler(HTTPException)
async def handle_http_error(e):
return jsonify(error = e.description), e.status_code

Expand Down
1,679 changes: 1,256 additions & 423 deletions poetry.lock

Large diffs are not rendered by default.

49 changes: 11 additions & 38 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,59 +7,31 @@ readme = "README.rst"

[tool.poetry.dependencies]
python = ">=3.9,<4"
aiocache = "0.11.1"
aiofiles = "0.6.0"
aiohttp = "3.7.3"
aioredis = "1.3.1"
async-timeout = "3.0.1"
asyncpg = "0.26.0"
attrs = "21.4.0"
beautifulsoup4 = "4.9.3"
aiocache = {version = "^0.11", extras = ["redis"]}
aiohttp = {version = "^3.9", extras = ["speedups"]}
asyncpg = "0.29.0"
billboard-py = "7.0.0"
blinker = "1.5"
certifi = "2022.12.7"
chardet = "3.0.4"
click = "7.1.2"
flask = "1.1.2"
gunicorn = "20.0.4"
h11 = "0.11.0"
h2 = "4.0.0"
hiredis = "1.1.0"
hpack = "4.0.0"
httptools = "0.1.1"
hypercorn = "0.13.2"
hyperframe = "6.0.1"
idna = "2.10"
itsdangerous = "2.0.0a1"
jinja2 = "3.0.0a1"
markupsafe = "2.0.0a1"
multidict = "5.1.0"
priority = "1.3.0"
pylast = "4.3.0"
pytelegraf = "0.3.3"
python-dateutil = "2.8.2"
python-levenshtein = "0.12.2"
levenshtein = "^0.25"
pytz = "2022.7"
quart = "0.14.1"
quart = "^0.19"
redis = "3.5.3"
requests = "2.25.1"
sentry-sdk = "0.19.5"
sentry-sdk = "*"
six = "1.15.0"
soupsieve = "2.3.2.post1"
spotipy = "2.16.1"
toml = "0.10.2"
typing-extensions = "3.7.4.3"
urllib3 = "1.26.9"
# Test error caused by https://stackoverflow.com/questions/65289720/attributeerror-retry-object-has-no-attribute-method-whitelist
# and seemingly lastfm (the exact error isn't in our code)
urllib3 = "1.25.1"
uvicorn = "0.20.0"
uvloop = "0.14.0"
werkzeug = "1.0.1"
wsproto = "1.1.0"
yarl = "1.6.3"


[tool.poetry.group.dev.dependencies]
pytest = "^8.1.1"
pytest-asyncio = "^0.23.5.post1"
pytest-asyncio = "^0.23.6"
mockredispy = "^2.9.3"

[build-system]
Expand All @@ -69,3 +41,4 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
lidarr-metadata-server = "lidarrmetadata.server:main"
lidarr-metadata-crawler = "lidarrmetadata.crawler:main"

3 changes: 2 additions & 1 deletion tests/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import pytest
import quart
from werkzeug.exceptions import BadRequest

import lidarrmetadata.app

Expand All @@ -25,6 +26,6 @@ async def test_get_search_query(s, expected):
@pytest.mark.asyncio
async def test_get_search_query_blank():
async with lidarrmetadata.app.app.test_request_context('/search?type=album&query='):
with pytest.raises(quart.exceptions.BadRequest) as e:
with pytest.raises(BadRequest) as e:
lidarrmetadata.app.get_search_query()
assert e.code == 400
15 changes: 15 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import asyncio

import pytest


# With package upgrades, this seems to be necessary to avoid errors of the loop
# being closed before tests are done
@pytest.fixture(scope="session")
def event_loop():
try:
loop = asyncio.get_running_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
yield loop
loop.close()
5 changes: 3 additions & 2 deletions tests/limit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
limit.redis.Redis = mockredis.mock_redis_client


class BaseTestRateLimiter(object):
class BaseTestRateLimiter:

def test_allowed(self):
for _ in range(5):
with self.limiter.limited():
Expand All @@ -28,7 +29,7 @@ def test_queue_popped(self):


class TestSimpleRateLimiter(BaseTestRateLimiter):
def setup(self):
def setup_method(self, _):
self.limiter = limit.SimpleRateLimiter(queue_size=5, time_delta=1000)


Expand Down
67 changes: 44 additions & 23 deletions tests/provider_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,58 @@


class TestWikipediaProvider:
def setup(self):
self.provider = provider.WikipediaProvider()
@classmethod
def setup_class(cls):
cls.provider = provider.WikipediaProvider()

@pytest.mark.asyncio
async def test_summary_invalid_url_empty(self):
assert '' == await self.provider.wikipedia_get_summary_from_title('fakeurl', 'en')

assert "" == await self.provider.wikipedia_get_summary_from_title(
"fakeurl", "en"
)

def test_title_from_url_invalid(self):
with pytest.raises(ValueError):
self.provider.wikipedia_title_from_url('fakeurl')
self.provider.wikipedia_title_from_url("fakeurl")

@pytest.mark.parametrize('url,expected', [
('http://en.wikipedia.org/wiki/Blink-182', ('Blink-182', 'en')),
('https://en.wikipedia.org/wiki/Blink-182', ('Blink-182', 'en')),
('http://af.wikipedia.org/wiki/Blink-182', ('Blink-182', 'af')),
('https://en.wikipedia.org/wiki/Avenged_Sevenfold', ('Avenged_Sevenfold', 'en')),
('https://en.wikipedia.org/wiki/Mumford_%26_Sons', ('Mumford_%26_Sons', 'en')),
('https://ja.wikipedia.org/wiki/%CE%9D_(%E3%83%90%E3%83%B3%E3%83%89)', ('%CE%9D_(%E3%83%90%E3%83%B3%E3%83%89)', 'ja')),
('https://wikipedia.org/wiki/Toni_Baldwin', ('Toni_Baldwin', 'en')),
('https://www.wikipedia.org/wiki/Toni_Baldwin', ('Toni_Baldwin', 'en'))
])
@pytest.mark.parametrize(
"url,expected",
[
("http://en.wikipedia.org/wiki/Blink-182", ("Blink-182", "en")),
("https://en.wikipedia.org/wiki/Blink-182", ("Blink-182", "en")),
("http://af.wikipedia.org/wiki/Blink-182", ("Blink-182", "af")),
(
"https://en.wikipedia.org/wiki/Avenged_Sevenfold",
("Avenged_Sevenfold", "en"),
),
(
"https://en.wikipedia.org/wiki/Mumford_%26_Sons",
("Mumford_%26_Sons", "en"),
),
(
"https://ja.wikipedia.org/wiki/%CE%9D_(%E3%83%90%E3%83%B3%E3%83%89)",
("%CE%9D_(%E3%83%90%E3%83%B3%E3%83%89)", "ja"),
),
("https://wikipedia.org/wiki/Toni_Baldwin", ("Toni_Baldwin", "en")),
("https://www.wikipedia.org/wiki/Toni_Baldwin", ("Toni_Baldwin", "en")),
],
)
def test_title_from_url(self, url, expected):
assert expected == self.provider.wikipedia_title_from_url(url)

@pytest.mark.parametrize('url,expected', [
('http://en.wikipedia.org/wiki/Blink-182', u'Blink-182'),
('https://ja.wikipedia.org/wiki/%CE%9D_(%E3%83%90%E3%83%B3%E3%83%89)', u'\u03bd'),
('https://www.wikidata.org/wiki/Q953918', 'Mumford & Sons'),
('https://www.wikidata.org/wiki/Q127939', 'Russian folk rock band'),
])

@pytest.mark.parametrize(
"url,expected",
[
("http://en.wikipedia.org/wiki/Blink-182", "Blink-182"),
(
"https://ja.wikipedia.org/wiki/%CE%9D_(%E3%83%90%E3%83%B3%E3%83%89)",
"Japanese visual kei rock band",
),
("https://www.wikidata.org/wiki/Q953918", "Mumford & Sons"),
("https://www.wikidata.org/wiki/Q127939", "Russian folk rock band"),
],
)
@pytest.mark.asyncio
async def test_summary_from_url(self, url, expected):
result, expiry = await self.provider.get_artist_overview(url)
assert result.startswith(expected)
assert result.startswith(expected), result