-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #530 from pyinat/search-controller
Add search controller / iNatClient.search()
- Loading branch information
Showing
6 changed files
with
131 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from typing import List, Optional | ||
|
||
from pyinaturalist.constants import MultiInt, MultiStr | ||
from pyinaturalist.controllers import BaseController | ||
from pyinaturalist.models import SearchResult | ||
from pyinaturalist.v1 import search | ||
|
||
|
||
class SearchController(BaseController): | ||
""":fa:`search` Unified text search""" | ||
|
||
def __call__( | ||
self, | ||
q: str, | ||
sources: Optional[MultiStr] = None, | ||
place_id: Optional[MultiInt] = None, | ||
locale: Optional[str] = None, | ||
preferred_place_id: Optional[int] = None, | ||
**params, | ||
) -> List[SearchResult]: | ||
"""A unified text search endpoint for places, projects, taxa, and/or users | ||
.. rubric:: Notes | ||
* API reference: :v1:`GET /search <Search/get_search>` | ||
Example: | ||
>>> response = client.search(q='odonat') | ||
>>> pprint(response) | ||
ID Type Score Name | ||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
47792 Taxon 9.45 Order Odonata (Dragonflies And Damselflies) | ||
113562 Place 7.70 Odonates of Peninsular India and Sri Lanka | ||
9978 Project 7.27 Ohio Dragonfly Survey (Ohio Odonata Survey) | ||
5665218 User 6.10 odonatachr | ||
Args: | ||
q: Search query | ||
sources: Object types to search | ||
place_id: Results must be associated with this place | ||
locale: Locale preference for taxon common names | ||
preferred_place_id: Place preference for regional taxon common names | ||
Returns: | ||
Response dict containing search results | ||
""" | ||
response = search( | ||
q, | ||
sources=sources, | ||
place_id=place_id, | ||
locale=locale, | ||
preferred_place_id=preferred_place_id, | ||
**params, | ||
) | ||
return SearchResult.from_json_list(response) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from datetime import datetime | ||
|
||
from pyinaturalist.client import iNatClient | ||
from pyinaturalist.constants import API_V1 | ||
from pyinaturalist.models import Place, Project, Taxon, User | ||
from test.sample_data import SAMPLE_DATA | ||
|
||
|
||
def test_search(requests_mock): | ||
"""Simulate /search results with one of each record type""" | ||
requests_mock.get( | ||
f'{API_V1}/search', | ||
json=SAMPLE_DATA['get_search'], | ||
status_code=200, | ||
) | ||
|
||
results = iNatClient().search([8348, 6432]) | ||
assert len(results) == 4 | ||
assert all(isinstance(result.score, float) for result in results) | ||
|
||
taxon_result = results[0] | ||
place_result = results[1] | ||
project_result = results[2] | ||
user_result = results[3] | ||
|
||
# Test value conversions | ||
assert taxon_result.type == 'Taxon' | ||
assert isinstance(taxon_result.record, Taxon) | ||
assert isinstance(taxon_result.record.created_at, datetime) | ||
assert taxon_result.record_name == 'Order Odonata (Dragonflies And Damselflies)' | ||
|
||
assert place_result.type == 'Place' | ||
assert isinstance(place_result.record, Place) | ||
assert isinstance(place_result.record.location[0], float) | ||
assert isinstance(place_result.record.location[1], float) | ||
assert place_result.record_name == 'Odonates of Peninsular India and Sri Lanka' | ||
|
||
assert project_result.type == 'Project' | ||
assert isinstance(project_result.record, Project) | ||
assert isinstance(project_result.record.last_post_at, datetime) | ||
assert project_result.record_name == 'Ohio Dragonfly Survey (Ohio Odonata Survey)' | ||
|
||
assert user_result.type == 'User' | ||
assert isinstance(user_result.record, User) | ||
assert isinstance(user_result.record.created_at, datetime) | ||
assert user_result.record_name == 'odonatanb' |