Skip to content
Merged
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
13 changes: 12 additions & 1 deletion src/wikibots/flickr.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
RATE_LIMIT_DELAYS = (60, 180, 300)


class _PatchedFlickrApi(FlickrApi):
# Temporary fix until flickr-photos-api handles missing <usage> attributes
def parse_single_photo_info(self, info_resp, *, photo_id):
usage_elem = info_resp.find("photo/usage")
if usage_elem is not None:
for attr in ("candownload", "canblog", "canprint", "canshare"):
if attr not in usage_elem.attrib:
usage_elem.set(attr, "0")
return super().parse_single_photo_info(info_resp, photo_id=photo_id)


class FlickrBot(BaseBot):
redis_prefix = "xQ6cz5J84Viw/K6FIcOH1kxJjfiS8jO56AoSmhBgO/A="
summary = "add [[Commons:Structured data|SDC]] based on metadata from Flickr"
Expand All @@ -32,7 +43,7 @@ class FlickrBot(BaseBot):
def __init__(self) -> None:
super().__init__()

self.flickr_api = FlickrApi.with_api_key(
self.flickr_api = _PatchedFlickrApi.with_api_key(
api_key=os.getenv("FLICKR_API_KEY", ""),
user_agent=self.user_agent,
)
Expand Down
35 changes: 33 additions & 2 deletions tests/test_flickr_rate_limit.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import cast
from unittest.mock import MagicMock, call, patch
from xml.etree import ElementTree as ET

import httpx
import pytest
from flickr_api import FlickrApi

from wikibots.flickr import FlickrBot
from wikibots.flickr import FlickrBot, _PatchedFlickrApi
from wikibots.lib.bot import RateLimitExhausted


Expand All @@ -13,7 +15,7 @@ def make_bot() -> FlickrBot:
with (
patch("wikibots.lib.bot.Redis") as mock_redis_cls,
patch("wikibots.lib.bot.requests.Session"),
patch("wikibots.flickr.FlickrApi"),
patch("wikibots.flickr._PatchedFlickrApi"),
Comment thread
greptile-apps[bot] marked this conversation as resolved.
):
mock_redis_cls.return_value.ping.return_value = True
bot = FlickrBot()
Expand All @@ -29,6 +31,35 @@ def make_429_error() -> httpx.HTTPStatusError:
)


def test_patched_flickr_api_fills_missing_usage_attrs():
info_resp = ET.fromstring(
'<rsp><photo><usage candownload="1" canblog="0" canshare="1"/></photo></rsp>'
)
with patch.object(FlickrApi, "parse_single_photo_info", return_value={}):
api = _PatchedFlickrApi.__new__(_PatchedFlickrApi)
api.parse_single_photo_info(info_resp, photo_id="55315578212")

usage = info_resp.find("photo/usage")
assert usage is not None
assert usage.attrib["canprint"] == "0"
assert usage.attrib["candownload"] == "1"
assert usage.attrib["canblog"] == "0"
assert usage.attrib["canshare"] == "1"


def test_patched_flickr_api_does_not_overwrite_existing_usage_attrs():
info_resp = ET.fromstring(
'<rsp><photo><usage candownload="1" canblog="1" canprint="1" canshare="1"/></photo></rsp>'
)
with patch.object(FlickrApi, "parse_single_photo_info", return_value={}):
api = _PatchedFlickrApi.__new__(_PatchedFlickrApi)
api.parse_single_photo_info(info_resp, photo_id="12345")

usage = info_resp.find("photo/usage")
assert usage is not None
assert usage.attrib["canprint"] == "1"


def test_rate_limit_retries_with_delays_then_raises(mocker):
bot = make_bot()
redis_mock = cast(MagicMock, bot.redis)
Expand Down