diff --git a/AUTHORS.rst b/AUTHORS.rst index 85434d2d..aa317d4e 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -10,6 +10,7 @@ Development Lead Contributors ------------ +* Jordan Cook * Peter Desmet * Stijn Van Hoey diff --git a/docs/infrastructure.rst b/docs/infrastructure.rst index 5a01eb17..80c57143 100644 --- a/docs/infrastructure.rst +++ b/docs/infrastructure.rst @@ -12,6 +12,13 @@ To build the doc locally:: $ tox -e docs +To preview:: + + # MacOS: + $ open docs/_build/index.html + # Linux: + $ xdg-open docs/_build/index.html + Hosted documentation (https://pyinaturalist.readthedocs.io/) is automatically updated when code gets pushed to GitHub. Testing diff --git a/docs/installation.rst b/docs/installation.rst index 4d403189..47da1efe 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -8,4 +8,10 @@ Simply use pip:: Or if you prefer using the development version:: - $ pip install git+https://github.com/niconoe/pyinaturalist.git \ No newline at end of file + $ pip install git+https://github.com/niconoe/pyinaturalist.git + +Or, to set up for local development (preferably in a new virtualenv):: + + $ git clone https://github.com/niconoe/pyinaturalist.git + $ cd pyinaturalist + $ pip install -Ue ".[dev]" diff --git a/pyinaturalist/__init__.py b/pyinaturalist/__init__.py index 2d47aa37..6d571c5f 100644 --- a/pyinaturalist/__init__.py +++ b/pyinaturalist/__init__.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +import logging __author__ = "Nicolas Noé" __email__ = "nicolas@niconoe.eu" @@ -7,3 +7,6 @@ DEFAULT_USER_AGENT = "Pyinaturalist/{version}".format(version=__version__) user_agent = DEFAULT_USER_AGENT + +# Enable logging for urllib and other external loggers +logging.basicConfig(level="DEBUG") diff --git a/pyinaturalist/constants.py b/pyinaturalist/constants.py index 89d76f44..971b3fb8 100644 --- a/pyinaturalist/constants.py +++ b/pyinaturalist/constants.py @@ -2,3 +2,31 @@ INAT_BASE_URL = "https://www.inaturalist.org" THROTTLING_DELAY = 1 # In seconds, support <0 floats such as 0.1 + +# Taxonomic ranks from Node API Swagger spec +RANKS = [ + "form", + "variety", + "subspecies", + "hybrid", + "species", + "genushybrid", + "genus", + "subtribe", + "tribe", + "supertribe", + "subfamily", + "family", + "epifamily", + "superfamily", + "infraorder", + "suborder", + "order", + "superorder", + "subclass", + "class", + "superclass", + "subphylum", + "phylum", + "kingdom", +] diff --git a/pyinaturalist/helpers.py b/pyinaturalist/helpers.py index e758abb0..85c41bed 100644 --- a/pyinaturalist/helpers.py +++ b/pyinaturalist/helpers.py @@ -1,4 +1,5 @@ import pyinaturalist +from typing import Dict, Any # For Python < 3.5 compatibility @@ -14,3 +15,18 @@ def get_user_agent(user_agent: str = None) -> str: return user_agent else: # Otherwise we have a global one in __init__.py (configurable, with sensible defaults) return pyinaturalist.user_agent + + +def concat_list_params(params) -> Dict[str, Any]: + """Convert any list parameters into an API-compatible (comma-delimited) string. + Will be url-encoded by requests. For example: `['k1', 'k2', 'k3'] -> k1%2Ck2%2Ck3` + """ + for k, v in params.items(): + if isinstance(v, list): + params[k] = ",".join(v) + return params + + +def strip_empty_params(params) -> Dict[str, Any]: + """Remove any request parameters with empty or ``None`` values.""" + return {k: v for k, v in params.items() if v} diff --git a/pyinaturalist/node_api.py b/pyinaturalist/node_api.py index e4ab8fd1..72ab6914 100644 --- a/pyinaturalist/node_api.py +++ b/pyinaturalist/node_api.py @@ -1,28 +1,38 @@ # Code to access the (read-only, but fast) Node based public iNaturalist API # See: http://api.inaturalist.org/v1/docs/ +from logging import getLogger from time import sleep from typing import Dict, Any, List import requests from urllib.parse import urljoin -from pyinaturalist.constants import THROTTLING_DELAY, INAT_NODE_API_BASE_URL +from pyinaturalist.constants import THROTTLING_DELAY, INAT_NODE_API_BASE_URL, RANKS from pyinaturalist.exceptions import ObservationNotFound -from pyinaturalist.helpers import merge_two_dicts, get_user_agent +from pyinaturalist.helpers import ( + merge_two_dicts, + get_user_agent, + concat_list_params, + strip_empty_params, +) PER_PAGE_RESULTS = 30 # Paginated queries: how many records do we ask per page? +logger = getLogger(__name__) + def make_inaturalist_api_get_call( endpoint: str, params: Dict, user_agent: str = None, **kwargs ) -> requests.Response: """Make an API call to iNaturalist. - endpoint is a string such as 'observations' !! do not put / in front + endpoint is a string such as 'observations' method: 'GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE' kwargs are passed to requests.request Returns a requests.Response object """ + params = strip_empty_params(params) + params = concat_list_params(params) headers = {"Accept": "application/json", "User-Agent": get_user_agent(user_agent)} response = requests.get( @@ -94,3 +104,89 @@ def get_all_observations(params: Dict, user_agent: str = None) -> List[Dict[str, sleep(THROTTLING_DELAY) id_above = results[-1]["id"] + + +def get_taxa_by_id(taxon_id, user_agent: str = None) -> Dict[str, Any]: + """ + Get one or more taxa by ID. + See: https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa_id + + :param: taxon_id: Get taxa with this ID. Multiple values are allowed. + + :returns: A list of dicts containing taxa results + """ + r = make_inaturalist_api_get_call( + "taxa/{}".format(taxon_id), {}, user_agent=user_agent + ) + r.raise_for_status() + return r.json() + + +def get_taxa( + user_agent: str = None, min_rank: str = None, max_rank: str = None, **params +) -> Dict[str, Any]: + """Given zero to many of following parameters, returns taxa matching the search criteria. + See https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa + + :param q: Name must begin with this value + :param is_active: Taxon is active + :param taxon_id: Only show taxa with this ID, or its descendants + :param parent_id: Taxon's parent must have this ID + :param rank: Taxon must have this exact rank + :param min_rank: Taxon must have this rank or higher; overrides ``rank`` + :param max_rank: Taxon must have this rank or lower; overrides ``rank`` + :param rank_level: Taxon must have this rank level. Some example values are 70 (kingdom), + 60 (phylum), 50 (class), 40 (order), 30 (family), 20 (genus), 10 (species), 5 (subspecies) + :param id_above: Must have an ID above this value + :param id_below: Must have an ID below this value + :param per_page: Number of results to return in a page. The maximum value is generally 200 + unless otherwise noted + :param locale: Locale preference for taxon common names + :param preferred_place_id: Place preference for regional taxon common names + :param only_id: Return only the record IDs + :param all_names: Include all taxon names in the response + + :returns: A list of dicts containing taxa results + """ + if min_rank or max_rank: + params["rank"] = get_rank_range(min_rank, max_rank) + r = make_inaturalist_api_get_call("taxa", params, user_agent=user_agent) + r.raise_for_status() + return r.json() + + +def get_taxa_autocomplete(user_agent: str = None, **params) -> Dict[str, Any]: + """Given a query string, returns taxa with names starting with the search term + See: https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa_autocomplete + + :param q: Name must begin with this value + :param is_active: Taxon is active + :param taxon_id: Only show taxa with this ID, or its descendants + :param rank: Taxon must have this rank + :param rank_level: Taxon must have this rank level. Some example values are 70 (kingdom), + 60 (phylum), 50 (class), 40 (order), 30 (family), 20 (genus), 10 (species), 5 (subspecies) + :param per_page: Number of results to return in a page. The maximum value is generally 200 unless otherwise noted + :param locale: Locale preference for taxon common names + :param preferred_place_id: Place preference for regional taxon common names + :param all_names: Include all taxon names in the response + + :returns: A list of dicts containing taxa results + """ + r = make_inaturalist_api_get_call( + "taxa/autocomplete", params, user_agent=user_agent + ) + r.raise_for_status() + return r.json() + + +def get_rank_range(min_rank: str = None, max_rank: str = None) -> List[str]: + """ Translate min and/or max rank into a list of ranks """ + min_rank_index = _get_rank_index(min_rank) if min_rank else 0 + max_rank_index = _get_rank_index(max_rank) + 1 if max_rank else len(RANKS) + return RANKS[min_rank_index:max_rank_index] + + +def _get_rank_index(rank: str) -> int: + if rank not in RANKS: + raise ValueError("Invalid rank") + return RANKS.index(rank) diff --git a/requirements.txt b/requirements.txt index 5c2ec87e..e10dd17e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,11 +27,14 @@ pyparsing==2.2.2 pytz==2018.5 readme-renderer==22.0 requests==2.20.0 -requests-mock==1.5.2 +requests-mock==1.7.0 requests-toolbelt==0.8.0 six==1.11.0 snowballstemmer==1.2.1 +sphinx==2.4.3 +sphinx-rtd-theme==0.4.3 sphinx-autodoc-typehints==1.10.3 +sphinx-rtd-theme==0.4.3 sphinxcontrib-websupport==1.1.0 toml==0.10.0 tox==3.5.2 diff --git a/setup.py b/setup.py index 4a07aa8f..6a985a18 100644 --- a/setup.py +++ b/setup.py @@ -25,10 +25,23 @@ author="Nicolas Noé", author_email="nicolas@niconoe.eu", url="https://github.com/niconoe/pyinaturalist", - packages=["pyinaturalist",], + packages=["pyinaturalist"], package_dir={"pyinaturalist": "pyinaturalist"}, include_package_data=True, install_requires=["requests>=2.21.0", "typing>=3.7.4"], + extras_require={ + "dev": [ + "black", + "flake8", + "mypy", + "pytest", + "requests-mock>=1.7", + "Sphinx", + "sphinx-autodoc-typehints", + "sphinx-rtd-theme", + "tox", + ] + }, license="MIT", zip_safe=False, keywords="pyinaturalist", diff --git a/test/sample_data/get_taxa.json b/test/sample_data/get_taxa.json new file mode 100644 index 00000000..9369402a --- /dev/null +++ b/test/sample_data/get_taxa.json @@ -0,0 +1,1413 @@ +{ + "total_results": 35, + "page": 1, + "per_page": 30, + "results": [ + { + "observations_count": 336, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Nicrophorus_vespilloides", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 53850, + "name": "Nicrophorus vespilloides", + "rank": "species", + "extinct": false, + "id": 70118, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751", + "attribution": "(c) salvatore_infanti, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/38359335/medium.jpg?1557348751", + "id": 38359335, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 70118 + ], + "matched_term": "Nicrophorus vespilloides", + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Lesser Vespillo Burying Beetle" + }, + { + "observations_count": 187, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Nicrophorus_vespillo", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 53850, + "name": "Nicrophorus vespillo", + "rank": "species", + "extinct": false, + "id": 131878, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/24573164/square.jpg?1536478624", + "attribution": "(c) Robin Bad, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/24573164/medium.jpg?1536478624", + "id": 24573164, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/24573164/square.jpg?1536478624" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 131878 + ], + "matched_term": "Nicrophorus vespillo", + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Vespillo Burying Beetle" + }, + { + "observations_count": 55, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47822/48091/372853/414448/49995/326181/488425/520026/124163", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Temnostoma_vespiforme", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 124163, + "name": "Temnostoma vespiforme", + "rank": "species", + "extinct": false, + "id": 124162, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/5925301/square.jpg?1545677110", + "attribution": "(c) Ouwesok, alguns direitos reservados (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/5925301/medium.jpg?1545677110", + "id": 5925301, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 1200, + "height": 1200 + }, + "url": "https://static.inaturalist.org/photos/5925301/square.jpg?1545677110" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47822, + 48091, + 372853, + 414448, + 49995, + 326181, + 488425, + 520026, + 124163, + 124162 + ], + "matched_term": "Temnostoma vespiforme", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 39, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47157/122746/51573/456401/366342/51684", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Synanthedon_vespiformis", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 51684, + "name": "Synanthedon vespiformis", + "rank": "species", + "extinct": false, + "id": 362871, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/1014675/square.jpg?1545557196", + "attribution": "(c) Tony Morris, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/1014675/medium.jpg?1545557196", + "id": 1014675, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 551, + "height": 473 + }, + "url": "https://static.inaturalist.org/photos/1014675/square.jpg?1545557196" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47157, + 122746, + 51573, + 456401, + 366342, + 51684, + 362871 + ], + "matched_term": "S\u00e9sie vespiforme", + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Yellow-legged Clearwing" + }, + { + "observations_count": 29, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/83201/372872/245155/252574", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Franklinothrips_vespiformis", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 252574, + "name": "Franklinothrips vespiformis", + "rank": "species", + "extinct": false, + "id": 270746, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/5079943/square.jpg?1475364205", + "attribution": "Sem direitos reservados", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/5079943/medium.jpg?1475364205", + "id": 5079943, + "license_code": "cc0", + "original_dimensions": { + "width": 819, + "height": 797 + }, + "url": "https://static.inaturalist.org/photos/5079943/square.jpg?1475364205" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 83201, + 372872, + 245155, + 252574, + 270746 + ], + "matched_term": "Franklinothrips vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 12, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740/52747/119344", + "is_active": true, + "flag_counts": { + "unresolved": 1, + "resolved": 2 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 119344, + "name": "Vespidae st1", + "rank": "species", + "extinct": false, + "id": 495392, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/5563170/square.jpg?1479599057", + "attribution": "(c) Stephen Thorpe, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/5563170/medium.jpg?1479599057", + "id": 5563170, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 781, + "height": 925 + }, + "url": "https://static.inaturalist.org/photos/5563170/square.jpg?1479599057" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 52747, + 119344, + 495392 + ], + "matched_term": "Vespidae st1", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 11, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47822/48091/372853/414448/49995/326181/520014/125658", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Ceriana_vespiformis", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 125658, + "name": "Ceriana vespiformis", + "rank": "species", + "extinct": false, + "id": 466251, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/3035009/square.jpg?1545634240", + "attribution": "(c) gailhampshire, some rights reserved (CC BY)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/3035009/medium.jpg?1545634240", + "id": 3035009, + "license_code": "cc-by", + "original_dimensions": { + "width": 832, + "height": 704 + }, + "url": "https://static.inaturalist.org/photos/3035009/square.jpg?1545634240" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47822, + 48091, + 372853, + 414448, + 49995, + 326181, + 520014, + 125658, + 466251 + ], + "matched_term": "Ceriana vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 7, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/47222/51955/210928/210927/507574/53067", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 53067, + "name": "Bembix vespiformis", + "rank": "species", + "extinct": false, + "id": 882585, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/33808490/square.jpeg?1554036738", + "attribution": "(c) birdnerd1, all rights reserved", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/33808490/medium.jpeg?1554036738", + "id": 33808490, + "license_code": null, + "original_dimensions": { + "width": 795, + "height": 1200 + }, + "url": "https://static.inaturalist.org/photos/33808490/square.jpeg?1554036738" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 47222, + 51955, + 210928, + 210927, + 507574, + 53067, + 882585 + ], + "matched_term": "Bembix vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 7, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47744/61267/372850/133754/48959/320199/482431/129424", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 129424, + "name": "Zelus vespiformis", + "rank": "species", + "extinct": false, + "id": 633966, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/5292283/square.jpg?1477056217", + "attribution": "(c) Paul, all rights reserved, uploaded by creaturesnapper", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/5292283/medium.jpg?1477056217", + "id": 5292283, + "license_code": null, + "original_dimensions": { + "width": 1580, + "height": 1064 + }, + "url": "https://static.inaturalist.org/photos/5292283/square.jpg?1477056217" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47744, + 61267, + 372850, + 133754, + 48959, + 320199, + 482431, + 129424, + 633966 + ], + "matched_term": "Zelus vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 4, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740/54028/201315/366768/563431", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 563431, + "name": "Ctenagenia vespiformis", + "rank": "species", + "extinct": false, + "id": 560666, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/30741827/square.jpg?1548679524", + "attribution": "(c) Paolo Mazzei, all rights reserved", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/30741827/medium.jpg?1548679524", + "id": 30741827, + "license_code": null, + "original_dimensions": { + "width": 800, + "height": 600 + }, + "url": "https://static.inaturalist.org/photos/30741827/square.jpg?1548679524" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 54028, + 201315, + 366768, + 563431, + 560666 + ], + "matched_term": "Ctenagenia vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 4, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740/52747/343248/531700/752711", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 1, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 752711, + "name": "Pseudopolybia vespiceps", + "rank": "species", + "extinct": false, + "id": 752716, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/54013958/square.jpeg?1571007464", + "attribution": "(c) adrianomaciel, all rights reserved", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/54013958/medium.jpeg?1571007464", + "id": 54013958, + "license_code": null, + "original_dimensions": { + "width": 2048, + "height": 1536 + }, + "url": "https://static.inaturalist.org/photos/54013958/square.jpeg?1571007464" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 52747, + 343248, + 531700, + 752711, + 752716 + ], + "matched_term": "Pseudopolybia vespiceps vespiceps", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 3, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740/52747/119344/428969", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 428969, + "name": "Hypodynerus vespiformis", + "rank": "species", + "extinct": false, + "id": 886207, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/29288906/square.jpg?1545155699", + "attribution": "(c) cmg_pdx, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/29288906/medium.jpg?1545155699", + "id": 29288906, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 1065, + "height": 795 + }, + "url": "https://static.inaturalist.org/photos/29288906/square.jpg?1545155699" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 52747, + 119344, + 428969, + 886207 + ], + "matched_term": "Hypodynerus vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 2, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47157/51269/51268", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Vespina", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 20, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 51268, + "name": "Vespina", + "rank": "genus", + "extinct": false, + "id": 84737, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47157, + 51269, + 51268, + 84737 + ], + "matched_term": "Vespina", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 2, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47744/61267/372868/51776/51777/319231/570423/605185", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 605185, + "name": "Moronopelios vespiformis", + "rank": "species", + "extinct": false, + "id": 605184, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/8932829/square.jpg?1499613099", + "attribution": "(c) kphuong7693, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/8932829/medium.jpg?1499613099", + "id": 8932829, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 1536, + "height": 2048 + }, + "url": "https://static.inaturalist.org/photos/8932829/square.jpg?1499613099" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47744, + 61267, + 372868, + 51776, + 51777, + 319231, + 570423, + 605185, + 605184 + ], + "matched_term": "Moronopelios vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 2, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47822/48091/372853/414448/49995/326181/488425/520024/465579", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 465579, + "name": "Sphecomyia vespiformis", + "rank": "species", + "extinct": false, + "id": 876493, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/33293202/square.jpg?1553351857", + "attribution": "(c) Andrei, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/33293202/medium.jpg?1553351857", + "id": 33293202, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 1480, + "height": 1163 + }, + "url": "https://static.inaturalist.org/photos/33293202/square.jpg?1553351857" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47822, + 48091, + 372853, + 414448, + 49995, + 326181, + 488425, + 520024, + 465579, + 876493 + ], + "matched_term": "Sphecomyia vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 1, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47822/48091/372865/354603/47982/639471/639475/623118", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 623118, + "name": "Codula vespiformis", + "rank": "species", + "extinct": false, + "id": 983565, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/30581879/square.jpg?1548308953", + "attribution": "(c) Richard Yank, all rights reserved", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/30581879/medium.jpg?1548308953", + "id": 30581879, + "license_code": null, + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/30581879/square.jpg?1548308953" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47822, + 48091, + 372865, + 354603, + 47982, + 639471, + 639475, + 623118, + 983565 + ], + "matched_term": "Codula vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/2/355675/47178/47286/51544/92786", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47178, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 92786, + "complete_rank": "subspecies", + "name": "Vespicula cypho", + "rank": "species", + "extinct": false, + "id": 621584, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 2, + 355675, + 47178, + 47286, + 51544, + 92786, + 621584 + ], + "matched_term": "Vespicula cypho", + "iconic_taxon_name": "Actinopterygii" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/2/355675/47178/47286/51544/92786", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47178, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 92786, + "complete_rank": "subspecies", + "name": "Vespicula trachinoides", + "rank": "species", + "extinct": false, + "id": 621585, + "default_photo": { + "square_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/75px-FMIB_47485_Prosopodasys_gogorzae.jpeg", + "attribution": "David Starr Jordan\n, no known copyright restrictions (public domain)", + "flags": [], + "medium_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/500px-FMIB_47485_Prosopodasys_gogorzae.jpeg", + "id": 33535972, + "license_code": "pd", + "original_dimensions": null, + "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/75px-FMIB_47485_Prosopodasys_gogorzae.jpeg" + }, + "ancestor_ids": [ + 48460, + 1, + 2, + 355675, + 47178, + 47286, + 51544, + 92786, + 621585 + ], + "matched_term": "Vespicula trachinoides", + "iconic_taxon_name": "Actinopterygii" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/2/355675/47178/47286/51544/92786", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47178, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 92786, + "complete_rank": "subspecies", + "name": "Vespicula zollingeri", + "rank": "species", + "extinct": false, + "id": 621586, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 2, + 355675, + 47178, + 47286, + 51544, + 92786, + 621586 + ], + "matched_term": "Vespicula zollingeri", + "iconic_taxon_name": "Actinopterygii" + }, + { + "observations_count": 0, + "taxon_schemes_count": 0, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740/51967/469073/893840", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 893840, + "name": "Pygodasis vespiformis", + "rank": "species", + "extinct": false, + "id": 915291, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 51967, + 469073, + 893840, + 915291 + ], + "matched_term": "Pygodasis vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/47170/48250/83715/83716/200006/450114", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47170, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 450114, + "name": "Candida vespimorsuum", + "rank": "species", + "extinct": false, + "id": 554174, + "default_photo": null, + "ancestor_ids": [ + 48460, + 47170, + 48250, + 83715, + 83716, + 200006, + 450114, + 554174 + ], + "matched_term": "Candida vespimorsuum", + "iconic_taxon_name": "Fungi" + }, + { + "observations_count": 0, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/69750/125448/519360/250566", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 250566, + "name": "Vespita woolleyi", + "rank": "species", + "extinct": false, + "id": 299443, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 69750, + 125448, + 519360, + 250566, + 299443 + ], + "matched_term": "Vespita woolleyi", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47157/47607/121850/47606/82089/82101/47988", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 47988, + "name": "Argyroeides vespina", + "rank": "species", + "extinct": false, + "id": 907874, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47157, + 47607, + 121850, + 47606, + 82089, + 82101, + 47988, + 907874 + ], + "matched_term": "Argyroeides vespina", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47822/48091/372865/354603/121526/699633", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 20, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 699633, + "name": "Vespiodes", + "rank": "genus", + "extinct": false, + "id": 646195, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47822, + 48091, + 372865, + 354603, + 121526, + 699633, + 646195 + ], + "matched_term": "Vespiodes", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/2/355675/47178/47286/51544", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Vespicula", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47178, + "rank_level": 20, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": 3, + "parent_id": 51544, + "complete_rank": "subspecies", + "name": "Vespicula", + "rank": "genus", + "extinct": false, + "id": 92786, + "default_photo": { + "square_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/75px-FMIB_47485_Prosopodasys_gogorzae.jpeg", + "attribution": "David Starr Jordan\n, no known copyright restrictions (public domain)", + "flags": [], + "medium_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/500px-FMIB_47485_Prosopodasys_gogorzae.jpeg", + "id": 33535972, + "license_code": "pd", + "original_dimensions": null, + "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/75px-FMIB_47485_Prosopodasys_gogorzae.jpeg" + }, + "ancestor_ids": [ + 48460, + 1, + 2, + 355675, + 47178, + 47286, + 51544, + 92786 + ], + "matched_term": "Vespicula", + "iconic_taxon_name": "Actinopterygii" + }, + { + "observations_count": 0, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/47951/373525/211904", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 211904, + "name": "Pseudopsis vespina", + "rank": "species", + "extinct": false, + "id": 267991, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 47951, + 373525, + 211904, + 267991 + ], + "matched_term": "Pseudopsis vespina", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/245097/47119/47118/120474/342614/367172/60351/60357", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47119, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 60357, + "complete_rank": "subspecies", + "name": "Mimetus vespillo", + "rank": "species", + "extinct": false, + "id": 833068, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 245097, + 47119, + 47118, + 120474, + 342614, + 367172, + 60351, + 60357, + 833068 + ], + "matched_term": "Mimetus vespillo", + "iconic_taxon_name": "Arachnida" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/47222/630955/47221/335715/340736/252728/572378", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 572378, + "name": "Odyneropsis vespiformis", + "rank": "species", + "extinct": false, + "id": 572367, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 47222, + 630955, + 47221, + 335715, + 340736, + 252728, + 572378, + 572367 + ], + "matched_term": "Odyneropsis vespiformis", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/69750/125448/519360", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 20, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 519360, + "name": "Vespita", + "rank": "genus", + "extinct": false, + "id": 250566, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 69750, + 125448, + 519360, + 250566 + ], + "matched_term": "Vespita", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47157/51269/51268/84737", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Vespina_quercivora", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 84737, + "name": "Vespina quercivora", + "rank": "species", + "extinct": false, + "id": 472528, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47157, + 51269, + 51268, + 84737, + 472528 + ], + "matched_term": "Vespina quercivora", + "iconic_taxon_name": "Insecta" + } + ] +} \ No newline at end of file diff --git a/test/sample_data/get_taxa_autocomplete.json b/test/sample_data/get_taxa_autocomplete.json new file mode 100644 index 00000000..e7822939 --- /dev/null +++ b/test/sample_data/get_taxa_autocomplete.json @@ -0,0 +1,467 @@ +{ + "total_results": 44, + "page": 1, + "per_page": 30, + "results": [ + { + "observations_count": 121793, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740", + "is_active": true, + "flag_counts": { + "unresolved": 1, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Vespidae", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 30, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 48740, + "name": "Vespidae", + "rank": "family", + "extinct": false, + "id": 52747, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/13765/square.jpg?1545358964", + "attribution": "(c) C\u00c3\u00a9cile Bassaglia, some rights reserved (CC BY-NC-SA)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/13765/medium.jpg?1545358964", + "id": 13765, + "license_code": "cc-by-nc-sa", + "original_dimensions": { + "width": 1024, + "height": 679 + }, + "url": "https://static.inaturalist.org/photos/13765/square.jpg?1545358964" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 52747 + ], + "matched_term": "Vespidae", + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Hornets, Paper Wasps, Potter Wasps, and Allies" + }, + { + "observations_count": 36400, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740/52747", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Vespinae", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 27, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 52747, + "name": "Vespinae", + "rank": "subfamily", + "extinct": false, + "id": 84738, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/11204897/square.jpeg?1508098617", + "attribution": "(c) brentnmoran, algunos derechos reservados (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/11204897/medium.jpeg?1508098617", + "id": 11204897, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/11204897/square.jpeg?1508098617" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 52747, + 84738 + ], + "matched_term": "Vespinae", + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Hornets and Yellowjackets" + }, + { + "observations_count": 187, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Nicrophorus_vespillo", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 53850, + "name": "Nicrophorus vespillo", + "rank": "species", + "extinct": false, + "id": 131878, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/24573164/square.jpg?1536478624", + "attribution": "(c) Robin Bad, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/24573164/medium.jpg?1536478624", + "id": 24573164, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/24573164/square.jpg?1536478624" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 131878 + ], + "matched_term": "Nicrophorus vespillo", + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Vespillo Burying Beetle" + }, + { + "observations_count": 12, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/326777/48740/52747/119344", + "is_active": true, + "flag_counts": { + "unresolved": 1, + "resolved": 2 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 119344, + "name": "Vespidae st1", + "rank": "species", + "extinct": false, + "id": 495392, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/5563170/square.jpg?1479599057", + "attribution": "(c) Stephen Thorpe, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/5563170/medium.jpg?1479599057", + "id": 5563170, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 781, + "height": 925 + }, + "url": "https://static.inaturalist.org/photos/5563170/square.jpg?1479599057" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 326777, + 48740, + 52747, + 119344, + 495392 + ], + "matched_term": "Vespidae st1", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 336, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Nicrophorus_vespilloides", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 53850, + "name": "Nicrophorus vespilloides", + "rank": "species", + "extinct": false, + "id": 70118, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751", + "attribution": "(c) salvatore_infanti, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/38359335/medium.jpg?1557348751", + "id": 38359335, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 70118 + ], + "matched_term": "Nicrophorus vespilloides", + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Lesser Vespillo Burying Beetle" + }, + { + "observations_count": 2, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47157/51269/51268", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Vespina", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 20, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 51268, + "name": "Vespina", + "rank": "genus", + "extinct": false, + "id": 84737, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47157, + 51269, + 51268, + 84737 + ], + "matched_term": "Vespina", + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/2/355675/47178/47286/51544/92786", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47178, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 92786, + "complete_rank": "subspecies", + "name": "Vespicula cypho", + "rank": "species", + "extinct": false, + "id": 621584, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 2, + 355675, + 47178, + 47286, + 51544, + 92786, + 621584 + ], + "matched_term": "Vespicula cypho", + "iconic_taxon_name": "Actinopterygii" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/2/355675/47178/47286/51544/92786", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47178, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 92786, + "complete_rank": "subspecies", + "name": "Vespicula trachinoides", + "rank": "species", + "extinct": false, + "id": 621585, + "default_photo": { + "square_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/75px-FMIB_47485_Prosopodasys_gogorzae.jpeg", + "attribution": "David Starr Jordan\n, no known copyright restrictions (public domain)", + "flags": [], + "medium_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/500px-FMIB_47485_Prosopodasys_gogorzae.jpeg", + "id": 33535972, + "license_code": "pd", + "original_dimensions": null, + "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/FMIB_47485_Prosopodasys_gogorzae.jpeg/75px-FMIB_47485_Prosopodasys_gogorzae.jpeg" + }, + "ancestor_ids": [ + 48460, + 1, + 2, + 355675, + 47178, + 47286, + 51544, + 92786, + 621585 + ], + "matched_term": "Vespicula trachinoides", + "iconic_taxon_name": "Actinopterygii" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/2/355675/47178/47286/51544/92786", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47178, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 92786, + "complete_rank": "subspecies", + "name": "Vespicula zollingeri", + "rank": "species", + "extinct": false, + "id": 621586, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 2, + 355675, + 47178, + 47286, + 51544, + 92786, + 621586 + ], + "matched_term": "Vespicula zollingeri", + "iconic_taxon_name": "Actinopterygii" + }, + { + "observations_count": 0, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47201/124417/69750/125448/519360/250566", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 250566, + "name": "Vespita woolleyi", + "rank": "species", + "extinct": false, + "id": 299443, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47201, + 124417, + 69750, + 125448, + 519360, + 250566, + 299443 + ], + "matched_term": "Vespita woolleyi", + "iconic_taxon_name": "Insecta" + } + ] +} \ No newline at end of file diff --git a/test/sample_data/get_taxa_by_id.json b/test/sample_data/get_taxa_by_id.json new file mode 100644 index 00000000..4703f041 --- /dev/null +++ b/test/sample_data/get_taxa_by_id.json @@ -0,0 +1,954 @@ +{ + "total_results": 1, + "page": 1, + "per_page": 30, + "results": [ + { + "observations_count": 336, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Nicrophorus_vespilloides", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "taxon_photos": [ + { + "taxon_id": 70118, + "photo": { + "flags": [], + "type": "LocalPhoto", + "url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751", + "square_url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751", + "native_page_url": "https://www.inaturalist.org/photos/38359335", + "native_photo_id": "38359335", + "small_url": "https://static.inaturalist.org/photos/38359335/small.jpg?1557348751", + "original_url": "https://static.inaturalist.org/photos/38359335/original.jpg?1557348751", + "attribution": "(c) salvatore_infanti, some rights reserved (CC BY-NC)", + "medium_url": "https://static.inaturalist.org/photos/38359335/medium.jpg?1557348751", + "id": 38359335, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "large_url": "https://static.inaturalist.org/photos/38359335/large.jpg?1557348751" + }, + "taxon": { + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850", + "min_species_ancestry": "48460,1,47120,372739,47158,184884,47208,71130,372870,48311,53849,204079,53850,70118", + "wikipedia_url": "http://en.wikipedia.org/wiki/Nicrophorus_vespilloides", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "created_at": "2011-05-01T07:20:55+00:00", + "taxon_changes_count": 0, + "complete_species_count": null, + "rank": "species", + "extinct": false, + "id": 70118, + "universal_search_rank": 336, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 70118 + ], + "observations_count": 336, + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "min_species_taxon_id": 70118, + "rank_level": 10, + "atlas_id": null, + "parent_id": 53850, + "name": "Nicrophorus vespilloides", + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751", + "attribution": "(c) salvatore_infanti, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/38359335/medium.jpg?1557348751", + "id": 38359335, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751" + }, + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Lesser Vespillo Burying Beetle" + } + } + ], + "rank_level": 10, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 53850, + "name": "Nicrophorus vespilloides", + "rank": "species", + "extinct": false, + "id": 70118, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751", + "attribution": "(c) salvatore_infanti, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/38359335/medium.jpg?1557348751", + "id": 38359335, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/38359335/square.jpg?1557348751" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Lesser Vespillo Burying Beetle", + "ancestors": [ + { + "observations_count": 19131154, + "taxon_schemes_count": 2, + "ancestry": "48460", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 7 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Animal", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 1, + "rank_level": 70, + "taxon_changes_count": 4, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 48460, + "complete_rank": "order", + "name": "Animalia", + "rank": "kingdom", + "extinct": false, + "id": 1, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/55133652/square.jpg?1572218969", + "attribution": "(c) Chien Lee, all rights reserved", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/55133652/medium.jpg?1572218969", + "id": 55133652, + "license_code": null, + "original_dimensions": { + "width": 1080, + "height": 721 + }, + "url": "https://static.inaturalist.org/photos/55133652/square.jpg?1572218969" + }, + "ancestor_ids": [ + 48460, + 1 + ], + "iconic_taxon_name": "Animalia", + "preferred_common_name": "Animals" + }, + { + "observations_count": 9438767, + "taxon_schemes_count": 2, + "ancestry": "48460/1", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 1 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Arthropod", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 1, + "rank_level": 60, + "taxon_changes_count": 2, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 1, + "complete_rank": "order", + "name": "Arthropoda", + "rank": "phylum", + "extinct": false, + "id": 47120, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/4115/square.jpg?1545349417", + "attribution": "(c) Damien du Toit, some rights reserved (CC BY)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/4115/medium.jpg?1545349417", + "id": 4115, + "license_code": "cc-by", + "original_dimensions": { + "width": 640, + "height": 480 + }, + "url": "https://static.inaturalist.org/photos/4115/square.jpg?1545349417" + }, + "ancestor_ids": [ + 48460, + 1, + 47120 + ], + "iconic_taxon_name": "Animalia", + "preferred_common_name": "Arthropods" + }, + { + "observations_count": 8226302, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Hexapoda", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 1, + "rank_level": 57, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 47120, + "complete_rank": "order", + "name": "Hexapoda", + "rank": "subphylum", + "extinct": false, + "id": 372739, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/29253963/square.jpg?1545062858", + "attribution": "(c) Alan Manson, some rights reserved (CC BY)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/29253963/medium.jpg?1545062858", + "id": 29253963, + "license_code": "cc-by", + "original_dimensions": { + "width": 1396, + "height": 1159 + }, + "url": "https://static.inaturalist.org/photos/29253963/square.jpg?1545062858" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739 + ], + "iconic_taxon_name": "Animalia", + "preferred_common_name": "Hexapods" + }, + { + "observations_count": 8212912, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739", + "is_active": true, + "flag_counts": { + "unresolved": 1, + "resolved": 29 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Insect", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 50, + "taxon_changes_count": 3, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 372739, + "complete_rank": "order", + "name": "Insecta", + "rank": "class", + "extinct": false, + "id": 47158, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/4744725/square.jpeg?1472813739", + "attribution": "(c) Jason Michael Crockwell, some rights reserved (CC BY-NC-ND)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/4744725/medium.jpeg?1472813739", + "id": 4744725, + "license_code": "cc-by-nc-nd", + "original_dimensions": { + "width": 2048, + "height": 1536 + }, + "url": "https://static.inaturalist.org/photos/4744725/square.jpeg?1472813739" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Insects" + }, + { + "observations_count": 8157224, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 3 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Pterygota", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 47, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 47158, + "complete_rank": "order", + "name": "Pterygota", + "rank": "subclass", + "extinct": false, + "id": 184884, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/33029706/square.jpg?1552913261", + "attribution": "(c) RAP, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/33029706/medium.jpg?1552913261", + "id": 33029706, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 900, + "height": 600 + }, + "url": "https://static.inaturalist.org/photos/33029706/square.jpg?1552913261" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Winged and Once-winged Insects" + }, + { + "observations_count": 979878, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 1 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Beetle", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 40, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 184884, + "name": "Coleoptera", + "rank": "order", + "extinct": false, + "id": 47208, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/33814912/square.jpeg?1554044732", + "attribution": "(c) Franz Anthony, algunos derechos reservados (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/33814912/medium.jpeg?1554044732", + "id": 33814912, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 1069, + "height": 1069 + }, + "url": "https://static.inaturalist.org/photos/33814912/square.jpeg?1554044732" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Beetles" + }, + { + "observations_count": 857104, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Polyphaga", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 37, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 47208, + "name": "Polyphaga", + "rank": "suborder", + "extinct": false, + "id": 71130, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/12466261/square.jpg?1513752231", + "attribution": "(c) Arnold Wijker, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/12466261/medium.jpg?1513752231", + "id": 12466261, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 800, + "height": 714 + }, + "url": "https://static.inaturalist.org/photos/12466261/square.jpg?1513752231" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Water, Rove, Scarab, Long-horned, Leaf, and Snout Beetles" + }, + { + "observations_count": 33616, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Staphyliniformia", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 35, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 71130, + "name": "Staphyliniformia", + "rank": "infraorder", + "extinct": false, + "id": 372870, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/14776949/square.jpg?1545718794", + "attribution": "(c) Pierre Bornand, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/14776949/medium.jpg?1545718794", + "id": 14776949, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1536 + }, + "url": "https://static.inaturalist.org/photos/14776949/square.jpg?1545718794" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Staphyliniform Beetles" + }, + { + "observations_count": 28105, + "taxon_schemes_count": 2, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Staphylinoidea", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 33, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 372870, + "name": "Staphylinoidea", + "rank": "superfamily", + "extinct": false, + "id": 48311, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/19900/square.jpg?1545365918", + "attribution": "(c) Robert, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/19900/medium.jpg?1545365918", + "id": 19900, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 960, + "height": 1280 + }, + "url": "https://static.inaturalist.org/photos/19900/square.jpg?1545365918" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Rove, Ant-like stone, and Carrion Beetles" + }, + { + "observations_count": 10508, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Silphidae", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 30, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 48311, + "name": "Silphidae", + "rank": "family", + "extinct": false, + "id": 53849, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/24573164/square.jpg?1536478624", + "attribution": "(c) Robin Bad, some rights reserved (CC BY-NC)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/24573164/medium.jpg?1536478624", + "id": 24573164, + "license_code": "cc-by-nc", + "original_dimensions": { + "width": 2048, + "height": 1365 + }, + "url": "https://static.inaturalist.org/photos/24573164/square.jpg?1536478624" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Burying and Carrion Beetles" + }, + { + "observations_count": 4508, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Nicrophorini", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 27, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 53849, + "name": "Nicrophorinae", + "rank": "subfamily", + "extinct": false, + "id": 204079, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/722951/square.jpg?1544743338", + "attribution": "(c) Natural History Museum: Coleoptera Section, some rights reserved (CC BY-NC-SA)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/722951/medium.jpg?1544743338", + "id": 722951, + "license_code": "cc-by-nc-sa", + "original_dimensions": { + "width": 374, + "height": 500 + }, + "url": "https://static.inaturalist.org/photos/722951/square.jpg?1544743338" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079 + ], + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 4506, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": "http://en.wikipedia.org/wiki/Burying_beetle", + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 20, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 204079, + "name": "Nicrophorus", + "rank": "genus", + "extinct": false, + "id": 53850, + "default_photo": { + "square_url": "https://static.inaturalist.org/photos/84004/square.jpg?1545389819", + "attribution": "(c) Dave, some rights reserved (CC BY-NC-SA)", + "flags": [], + "medium_url": "https://static.inaturalist.org/photos/84004/medium.jpg?1545389819", + "id": 84004, + "license_code": "cc-by-nc-sa", + "original_dimensions": { + "width": 660, + "height": 747 + }, + "url": "https://static.inaturalist.org/photos/84004/square.jpg?1545389819" + }, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850 + ], + "iconic_taxon_name": "Insecta", + "preferred_common_name": "Burying Beetles" + } + ], + "children": [ + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850/70118", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 5, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 70118, + "name": "Nicrophorus vespilloides aurora", + "rank": "variety", + "extinct": false, + "id": 70114, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 70118, + 70114 + ], + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850/70118", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 5, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 70118, + "name": "Nicrophorus vespilloides sylvivagus", + "rank": "subspecies", + "extinct": false, + "id": 70116, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 70118, + 70116 + ], + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850/70118", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 5, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 70118, + "name": "Nicrophorus vespilloides altumi", + "rank": "form", + "extinct": false, + "id": 70115, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 70118, + 70115 + ], + "iconic_taxon_name": "Insecta" + }, + { + "observations_count": 0, + "taxon_schemes_count": 1, + "ancestry": "48460/1/47120/372739/47158/184884/47208/71130/372870/48311/53849/204079/53850/70118", + "is_active": true, + "flag_counts": { + "unresolved": 0, + "resolved": 0 + }, + "wikipedia_url": null, + "current_synonymous_taxon_ids": null, + "iconic_taxon_id": 47158, + "rank_level": 5, + "taxon_changes_count": 0, + "atlas_id": null, + "complete_species_count": null, + "parent_id": 70118, + "name": "Nicrophorus vespilloides subfasciatus", + "rank": "variety", + "extinct": false, + "id": 70117, + "default_photo": null, + "ancestor_ids": [ + 48460, + 1, + 47120, + 372739, + 47158, + 184884, + 47208, + 71130, + 372870, + 48311, + 53849, + 204079, + 53850, + 70118, + 70117 + ], + "iconic_taxon_name": "Insecta" + } + ], + "conservation_statuses": [], + "listed_taxa_count": 4, + "listed_taxa": [ + { + "id": 5577060, + "taxon_id": 70118, + "establishment_means": "native", + "place": { + "id": 1, + "name": "United States", + "display_name": "United States", + "admin_level": 0, + "ancestor_place_ids": [ + 97394, + 1 + ] + }, + "list": { + "id": 299, + "title": "United States Check List" + } + }, + { + "id": 5680497, + "taxon_id": 70118, + "establishment_means": "native", + "place": { + "id": 6712, + "name": "Canada", + "display_name": "Canada", + "admin_level": 0, + "ancestor_place_ids": [ + 97394, + 6712 + ] + }, + "list": { + "id": 187791, + "title": "NatureServe Canada" + } + }, + { + "id": 5577061, + "taxon_id": 70118, + "establishment_means": "native", + "place": { + "id": 6, + "name": "Alaska", + "display_name": "Alaska, US", + "admin_level": 1, + "ancestor_place_ids": [ + 97394, + 1, + 6 + ] + }, + "list": { + "id": 304, + "title": "Alaska Check List" + } + }, + { + "id": 5577062, + "taxon_id": 70118, + "establishment_means": "native", + "place": { + "id": 341, + "name": "Kenai Peninsula", + "display_name": "Kenai Peninsula County, US, AK", + "admin_level": 2, + "ancestor_place_ids": [ + 97394, + 1, + 6, + 341 + ] + }, + "list": { + "id": 639, + "title": "Kenai Peninsula Borough Check List" + } + } + ], + "wikipedia_summary": "Nicrophorus vespilloides is a burying beetle described by Johann Friedrich Wilhelm Herbst in 1783." + } + ] +} \ No newline at end of file diff --git a/test/test_pyinaturalist.py b/test/test_pyinaturalist.py index 16463a84..16545219 100755 --- a/test/test_pyinaturalist.py +++ b/test/test_pyinaturalist.py @@ -4,13 +4,21 @@ import json import os from datetime import datetime, timedelta +from unittest.mock import patch import pytest import requests_mock from requests import HTTPError +from urllib.parse import urlencode, urljoin import pyinaturalist -from pyinaturalist.node_api import get_observation +from pyinaturalist.constants import INAT_NODE_API_BASE_URL +from pyinaturalist.node_api import ( + get_observation, + get_taxa, + get_taxa_by_id, + get_taxa_autocomplete, +) from pyinaturalist.rest_api import ( get_access_token, get_all_observation_fields, @@ -37,11 +45,9 @@ def _load_sample_json(filename): class TestNodeApi(object): - @requests_mock.Mocker(kw="mock") - def test_get_observation(self, **kwargs): - mock = kwargs["mock"] - mock.get( - "https://api.inaturalist.org/v1/observations?id=16227955", + def test_get_observation(self, requests_mock): + requests_mock.get( + urljoin(INAT_NODE_API_BASE_URL, "observations?id=16227955"), json=_load_sample_json("get_observation.json"), status_code=200, ) @@ -52,17 +58,94 @@ def test_get_observation(self, **kwargs): assert obs_data["user"]["login"] == "niconoe" assert len(obs_data["photos"]) == 2 - @requests_mock.Mocker(kw="mock") - def test_get_non_existent_observation(self, **kwargs): - mock = kwargs["mock"] - mock.get( - "https://api.inaturalist.org/v1/observations?id=99999999", + def test_get_non_existent_observation(self, requests_mock): + requests_mock.get( + urljoin(INAT_NODE_API_BASE_URL, "observations?id=99999999"), json=_load_sample_json("get_nonexistent_observation.json"), status_code=200, ) with pytest.raises(ObservationNotFound): get_observation(observation_id=99999999) + def test_get_taxa(self, requests_mock): + params = urlencode({"q": "vespi", "rank": "genus,subgenus,species"}) + requests_mock.get( + urljoin(INAT_NODE_API_BASE_URL, "taxa?" + params), + json=_load_sample_json("get_taxa.json"), + status_code=200, + ) + + response = get_taxa(q="vespi", rank=["genus", "subgenus", "species"]) + first_result = response["results"][0] + + assert len(response["results"]) == 30 + assert response["total_results"] == 35 + assert first_result["id"] == 70118 + assert first_result["name"] == "Nicrophorus vespilloides" + assert first_result["rank"] == "species" + assert first_result["is_active"] is True + assert len(first_result["ancestor_ids"]) == 14 + + CLASS_AND_HIGHER = ["class", "superclass", "subphylum", "phylum", "kingdom"] + SPECIES_AND_LOWER = ["form", "variety", "subspecies", "hybrid", "species"] + CLASS_THOUGH_PHYLUM = ["class", "superclass", "subphylum", "phylum"] + + @pytest.mark.parametrize( + "params, expected_ranks", + [ + ({"rank": "genus"}, "genus"), + ({"min_rank": "class"}, CLASS_AND_HIGHER), + ({"max_rank": "species"}, SPECIES_AND_LOWER), + ({"min_rank": "class", "max_rank": "phylum"}, CLASS_THOUGH_PHYLUM), + ({"max_rank": "species", "rank": "override_me"}, SPECIES_AND_LOWER), + ], + ) + @patch("pyinaturalist.node_api.make_inaturalist_api_get_call") + def test_get_taxa_by_rank_range( + self, mock_inaturalist_api_get_call, params, expected_ranks, + ): + # Make sure custom rank params result in the correct 'rank' param value + get_taxa(**params) + mock_inaturalist_api_get_call.assert_called_with( + "taxa", {"rank": expected_ranks}, user_agent=None + ) + + def test_get_taxa_by_id(self, requests_mock): + taxon_id = 70118 + requests_mock.get( + urljoin(INAT_NODE_API_BASE_URL, "taxa/" + str(taxon_id)), + json=_load_sample_json("get_taxa_by_id.json"), + status_code=200, + ) + + response = get_taxa_by_id(taxon_id) + result = response["results"][0] + assert len(response["results"]) == 1 + assert result["id"] == taxon_id + assert result["name"] == "Nicrophorus vespilloides" + assert result["rank"] == "species" + assert result["is_active"] is True + assert len(result["ancestors"]) == 12 + + def test_get_taxa_autocomplete(self, requests_mock): + requests_mock.get( + urljoin(INAT_NODE_API_BASE_URL, "taxa/autocomplete?q=vespi"), + json=_load_sample_json("get_taxa_autocomplete.json"), + status_code=200, + ) + + response = get_taxa_autocomplete(q="vespi") + first_result = response["results"][0] + + assert len(response["results"]) == 10 + assert response["total_results"] == 44 + assert first_result["matched_term"] == "Vespidae" + assert first_result["id"] == 52747 + assert first_result["name"] == "Vespidae" + assert first_result["rank"] == "family" + assert first_result["is_active"] is True + assert len(first_result["ancestor_ids"]) == 11 + class TestRestApi(object): @requests_mock.Mocker(kw="mock") @@ -325,7 +408,7 @@ def test_user_agent(self, **kwargs): # TODO: test for all functions that access the inaturalist API? mock = kwargs["mock"] mock.get( - "https://api.inaturalist.org/v1/observations?id=16227955", + urljoin(INAT_NODE_API_BASE_URL, "observations?id=16227955"), json=_load_sample_json("get_observation.json"), status_code=200, ) diff --git a/tox.ini b/tox.ini index 66a6694f..8a4e14aa 100644 --- a/tox.ini +++ b/tox.ini @@ -5,8 +5,8 @@ envlist = py33, py34, py35, py36, py37, py38, style, docs, mypy setenv = PYTHONPATH = {toxinidir}:{toxinidir}/pyinaturalist deps = - pytest==3.10.1 - requests-mock==1.5.2 + pytest==4.6.9 + requests-mock==1.7.0 commands = py.test --basetemp={envtmpdir} @@ -16,13 +16,11 @@ deps = flake8 commands = python setup.py flake8 - + [testenv:docs] changedir=docs/ deps = -r{toxinidir}/requirements.txt - sphinx - sphinx_rtd_theme whitelist_externals = make commands = make clean