Skip to content

Commit

Permalink
feat(aiohttp): Add async search generator
Browse files Browse the repository at this point in the history
The async generator (`asearch`) allows iterating through all 100 results
which are available from the API. It does this by requesting new pages
of results when the results are exhausted.
  • Loading branch information
Minion3665 committed Sep 17, 2024
1 parent 002dfbc commit 78dfc88
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 34 deletions.
27 changes: 27 additions & 0 deletions google_custom_search/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from .errors import AsyncError, ApiNotEnabled
from .types import Item

from typing import AsyncGenerator


class BaseAdapter(metaclass=ABCMeta):
"""This is the base class for adapters.
Expand Down Expand Up @@ -42,6 +44,9 @@ def request(self, method: str, path: str, *args, **kwargs) -> Any:
def search(self, *args, **kwargs) -> List[Item]:
...

async def asearch(self, *_args, **_kwargs) -> AsyncGenerator[Item, None]:
raise NotImplementedError("You can only use 'asearch' on an asynchronous adapter")

def _from_dict(self, data: dict) -> List[Item]:
if data.get('error'):
raise ApiNotEnabled(
Expand Down Expand Up @@ -108,3 +113,25 @@ async def search(self, *args, **kwargs) -> List[Item]:
"GET", "/", params=self._payload_maker(*args, **kwargs)
)
return self._from_dict(r)

async def asearch(self, *args, **kwargs) -> AsyncGenerator[Item, None]:
limit = kwargs.get("limit", 100)

if "limit" in kwargs:
del kwargs["limit"]

while True:
page = await self.search(*args, **kwargs)

for result in page:
yield result

kwargs["start"] = kwargs.get("start", 1) + kwargs.get("num", 10)

if kwargs["start"] + kwargs.get("num", 10) > limit:
kwargs["num"] = limit - kwargs["start"] + 1 # both ends of the range are inclusive

if kwargs.get("num", 10) <= 0:
return


72 changes: 38 additions & 34 deletions google_custom_search/search.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
# google-custom-seaerch - search

from typing import List

from .types import Item
from .adapter import BaseAdapter


class CustomSearch:
"""This is the class used when using Google Custom Search.
Args:
adapter (BaseAdapter): Insert adapter
"""
APIURL: str = "https://www.googleapis.com/customsearch/v1"

def __init__(self, adapter: BaseAdapter):
self.adapter = adapter

def search(self, *args, **kwargs) -> List[Item]:
"""This is searched using api.
Args:
query (str): Search keyword
safe (bool): Using safe mode
filter_ (filter): Use filter mode
Returns:
List[Item]: return result
Raises:
ApiNotEnabled: api is not invalid
"""
return self.adapter.search(*args, **kwargs)
# google-custom-seaerch - search

from typing import List, AsyncGenerator

from .types import Item
from .adapter import BaseAdapter


class CustomSearch:
"""This is the class used when using Google Custom Search.
Args:
adapter (BaseAdapter): Insert adapter
"""
APIURL: str = "https://www.googleapis.com/customsearch/v1"

def __init__(self, adapter: BaseAdapter):
self.adapter = adapter

def search(self, *args, **kwargs) -> List[Item]:
"""This is searched using api.
Args:
query (str): Search keyword
safe (bool): Using safe mode
filter_ (filter): Use filter mode
Returns:
List[Item]: return result
Raises:
ApiNotEnabled: api is not invalid
"""
return self.adapter.search(*args, **kwargs)

async def asearch(self, *args, **kwargs) -> AsyncGenerator[Item, None]:
async for item in self.adapter.asearch(*args, **kwargs):
yield item

0 comments on commit 78dfc88

Please sign in to comment.