import asyncio
import time
from pathlib import Path
from PIL import Image
from aoptk.literature.id import ID
[docs]
class AsyncRequestLimiter:
"""Asynchronous request limiter to control the rate of API calls."""
def __init__(self, requests_per_second: int):
[docs]
self.min_interval = 1.0 / requests_per_second
[docs]
self._lock = asyncio.Lock()
[docs]
self._next_allowed = 0.0
[docs]
async def wait_turn(self) -> None:
"""Wait until it's the turn for the next request based on the rate limit."""
async with self._lock:
now = time.monotonic()
if now < self._next_allowed:
await asyncio.sleep(self._next_allowed - now)
now = time.monotonic()
self._next_allowed = now + self.min_interval
[docs]
def is_europepmc_id(publication_id: ID) -> bool:
"""Check if the given publication ID is a EuropePMC ID."""
return bool(str(publication_id).startswith("PMC"))
[docs]
def convert_to_png(inpath: Path, outpath: Path) -> None:
"""Convert an image to PNG format.
Args:
inpath: The path of the input image.
outpath: The path where the converted image will be saved.
"""
with Image.open(inpath) as img:
img.convert("RGB").save(outpath) if img.mode not in ["RGB", "RGBA"] else img.save(outpath)
inpath.unlink()
[docs]
def remove_pmc_prefix(ids: list[ID]) -> list[ID]:
"""Remove the 'PMC' prefix from ID.
Args:
ids (list[ID]): A list of IDs to remove the prefix from.
"""
return [ID(str(publication_id)[3:]) for publication_id in ids]