Python client for the iNaturalist APIs
Project description
pyinaturalist
Python client for the iNaturalist APIs. See full documentation at https://pyinaturalist.readthedocs.io.
Installation
Install the latest stable version with pip:
$ pip install pyinaturalist
Or, if you would like to use the latest development (non-stable) version:
$ pip install --pre pyinaturalist
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]"
Development Status
Pyinaturalist is under active development. Currently, a handful of the most relevant API endpoints are implemented, including:
- Searching, creating, and updating observations and observation fields
- Searching for places, projects, species, and species counts
- Text search autocompletion for species and places
See below for some examples, see Endpoints for a complete list of implemented endpoints, and see Issues for planned & proposed features.
More endpoints will continue to be added as they are needed. Please create an issue if there is an endpoint you would like to have added, and PRs are welcome!
Note:
The two iNaturalist APIs expose a combined total of 103 endpoints*. Some of these are generally useful and could potentially be added to pyinaturalist, but many others are primarily for internal use by the iNaturalist web application and mobile apps, and are unlikely to be added unless there are specific use cases for them.
*As of 2020-10-01: 37 in REST API, 65 in Node API, and 1 undocumented
Examples
Observations
Search observations
from pyinaturalist.node_api import get_all_observations
obs = get_all_observations(user_id='my_username')
Get an access token
For authenticated API calls (creating/updating/deleting data), you first need to obtain an access token. This requires creating an iNaturalist app.
from pyinaturalist.rest_api import get_access_token
token = get_access_token(
username='<your_inaturalist_username>',
password='<your_inaturalist_password>',
app_id='<your_inaturalist_app_id>',
app_secret='<your_inaturalist_app_secret>',
)
Create a new observation
from pyinaturalist.rest_api import create_observation
from datetime import datetime
response = create_observation(
taxon_id=54327, # Vespa Crabro
observed_on_string=datetime.now().isoformat(),
time_zone='Brussels',
description='This is a free text comment for the observation',
tag_list='wasp, Belgium',
latitude=50.647143,
longitude=4.360216,
positional_accuracy=50, # meters,
# sets vespawatch_id (an observation field whose ID is 9613) to the value '100'.
observation_field_values_attributes=[
{'observation_field_id': 9613,'value': 100},
],
access_token=token,
)
new_observation_id = response[0]['id']
Upload a picture for this observation
from pyinaturalist.rest_api import add_photo_to_observation
r = add_photo_to_observation(
new_observation_id,
access_token=token,
photo='/Users/nicolasnoe/vespa.jpg',
)
Update an existing observation of yours
from pyinaturalist.rest_api import update_observation
r = update_observation(
17932425,
access_token=token,
description='updated description !',
)
Get a list of all (globally available) observation fields
from pyinaturalist.rest_api import get_all_observation_fields
r = get_all_observation_fields(search_query="DNA")
Set an observation field value on an existing observation
from pyinaturalist.rest_api import put_observation_field_values
put_observation_field_values(
observation_id=7345179,
observation_field_id=9613,
value=250,
access_token=token,
)
Get observation data in alternative formats
A separate endpoint can provide other data formats, including Darwin Core, KML, and CSV:
from pyinaturalist.rest_api import get_observations
obs = get_observations(user_id='niconoe', response_format='dwc')
See available parameters and formats
Get observation species counts
There is an additional endpoint to get counts of observations by species. On the iNaturalist web UI, this information can be found on the 'Species' tab of search results. For example, to get the counts of all your own research-grade observations:
from pyinaturalist.node_api import get_observation_species_counts
obs_counts = get_observation_species_counts(user_id='my_username', quality_grade='research')
Taxonomy
Search species and other taxa
Let's say you partially remember either a genus or family name that started with 'vespi'-something:
>>> from pyinaturalist.node_api import get_taxa
>>>
>>> response = get_taxa(q="vespi", rank=["genus", "family"])
>>> print({taxon["id"]: taxon["name"] for taxon in response["results"]})
{52747: "Vespidae", 84737: "Vespina", 92786: "Vespicula", 646195: "Vespiodes", ...}
Oh, that's right, it was 'Vespidae'! Now let's find all of its subfamilies using its taxon ID from the results above:
>>> response = get_taxa(parent_id=52747)
>>> print({taxon["id"]: taxon["name"] for taxon in response["results"]})
{343248: "Polistinae", 84738: "Vespinae", 119344: "Eumeninae", 121511: "Masarinae", ...}
Get a species by ID
Let's find out more about this 'Polistinae' genus. We could search for it by name or by ID, but since we already know the ID from the previous search, let's use that:
>>> from pyinaturalist.node_api import get_taxa_by_id
>>> response = get_taxa_by_id(343248)
There is a lot of info in there, but let's just get the basics for now:
>>> basic_fields = ["preferred_common_name", "observations_count", "wikipedia_url", "wikipedia_summary"]
>>> print({f: response["results"][0][f] for f in basic_fields})
{
"preferred_common_name": "Paper Wasps",
"observations_count": 69728,
"wikipedia_url": "http://en.wikipedia.org/wiki/Polistinae",
"wikipedia_summary": "The Polistinae are eusocial wasps closely related to the more familiar yellow jackets...",
}
Taxon autocomplete
This is a text search-optimized endpoint that provides autocompletion in the Naturalist web UI:
This one is a bit more niche, but it provides a fast way to search the iNaturalist taxonomy database. Here is an example that will run searches from console input:
from pyinaturalist.node_api import get_taxa_autocomplete
while True:
query = input("> ")
response = get_taxa_autocomplete(q=query, minify=True)
print("\n".join(response["results"]))
Example usage:
> opilio
527573: Genus Opilio
47367: Order Opiliones (Harvestmen)
84644: Species Phalangium opilio (European Harvestman)
527419: Subfamily Opilioninae
...
> coleo
372759: Subclass Coleoidea (Coleoids)
47208: Order Coleoptera (Beetles)
359229: Species Coleotechnites florae (Coleotechnites Flower Moth)
53502: Genus Brickellia (brickellbushes)
...
<Ctrl-C>
If you get unexpected matches, the search likely matched a synonym, either in the form of a
common name or an alternative classification. Check the matched_term
property for more
info. For example:
>>> first_result = get_taxa_autocomplete(q='zygoca')['results'][0]
>>> first_result["name"]
"Schlumbergera truncata"
>>> first_result["matched_term"]
"Zygocactus truncatus" # An older synonym for Schlumbergera
History
0.11.0 (2020-11-04)
New Endpoints
- Added new functions for Node API Places endpoints:
get_places_by_id()
get_places_nearby()
get_places_autocomplete()
- Added new functions for Node API Projects endpoints:
get_projects()
get_projects_by_id()
- Added new function for an additional Node API Observation endpoint:
get_observation_species_counts()
get_all_observation_species_counts()
Modified Endpoints
- Added support for simplified observation field syntax (
observation_fields={id: value}
) forcreate_observations()
andupdate_observation()
- Updated
node_api.get_taxa_by_id()
to accept multiple IDs - Updated
rest_api.get_observations()
with type conversion from strings to floats for response lat/long coordinates. Only applies to JSON response format. - Updated
node_api.get_taxa_autocomplete()
with optionalmin_rank
andmax_rank
parameters, for consistency withget_taxa()
- Using the
params
positional argument for the handful of functions that used it will raise aDeprecationWarning
, but will otherwise still be functional until0.12
- Renamed
search_query
argument toq
to be consistent with API request parameters - Using the
search_query
argument forrest_api.get_observation_fields()
andrest_api.get_all_observation_fields()
will raise aDeprecationWarning
, but will otherwise still be functional until0.12
- Renamed
create_observations()
tocreate_observation()
, as this only supports creating a single observation per call. This is aliased tocreate_observations()
for backwards-compatibility, but will raise aDeprecationWarning
.
Documentation & Usability
- Added example response data to docs all endpoints
- Added links to official API reference to docs for all endpoints
- Added full API request parameters to all API functions, in the form of keyword arguments with type annotations and docstrings
- Added complete table of iNaturalist API endpoints and endpoints implemented by pyinaturalist
- Added and improved usage examples
- Numerous other documentation improvements
- Made all API function signatures consistent by taking request params as keyword arguments
Other Changes
- Dropped testing & support for python 3.4
- Added testing & support for python 3.9
- Added parameter validation for multiple-choice request parameters
0.10.0 (2020-06-16)
New Endpoints
- Added new Observation endpoint:
rest_api.get_observations()
, with 6 additional observation response formats, including GeoJSON, Darwin Core, and others
Modified Endpoints
- Added
minify
option tonode_api.get_taxa_autocomplete()
Other Changes
- Added more info & examples to README for taxa endpoints, and other documentation improvements
- Added conversion for all date and datetime parameters to timezone-aware ISO 8601 timestamps
- Added a dry-run mode to mock out API requests for testing
- Set up pre-release builds for latest development version
0.9.1 (2020-05-26)
- Bugfix: proper support for boolean and integer list parameters (see https://github.com/niconoe/pyinaturalist/issues/17).
0.9.0 (2020-05-06)
New Endpoints
-
Added new functions for Node API Taxa endpoints:
node_api.get_taxa()
node_api.get_taxa_autocomplete()
node_api.get_taxa_by_id()
0.8.0 (2019-07-11)
- All functions now take an optional
user-agent <https://en.wikipedia.org/wiki/User_agent>
_ parameter in order to identify yourself to iNaturalist. If not set,Pyinaturalist/<VERSION>
will be used.
0.7.0 (2019-05-08)
rest_api.delete_observation()
now raisesObservationNotFound
if the observation doesn't exist- minor dependencies update for security reasons
0.6.0 (2018-11-15)
- New function:
rest_api.delete_observation()
0.5.0 (2018-11-05)
- New function:
node_api.get_observation()
0.4.0 (2018-11-05)
create_observation()
now raises exceptions in case of errors.
0.3.0 (2018-11-05)
update_observation()
now raises exceptions in case of errors.
0.2.0 (2018-10-31)
- Better infrastructure (type annotations, documentation, ...)
- Dropped support for Python 2.
- New function:
update_observation()
rest_api.AuthenticationError
is nowexceptions.AuthenticationError
0.1.0 (2018-10-10)
- First release on PyPI.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pyinaturalist-0.11.0.tar.gz
.
File metadata
- Download URL: pyinaturalist-0.11.0.tar.gz
- Upload date:
- Size: 44.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.8.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c8e12304b8ee79185baa6bac79542ed1c340395354a72008b9bff31dd888c8bc |
|
MD5 | 8de7e60700b2092f1a73d147e5ff70b2 |
|
BLAKE2b-256 | b6dfd0637337cfa44938e7ff20abb6edf9347dfb21aff1c3b8e0a1a4e7295501 |
File details
Details for the file pyinaturalist-0.11.0-py2.py3-none-any.whl
.
File metadata
- Download URL: pyinaturalist-0.11.0-py2.py3-none-any.whl
- Upload date:
- Size: 45.8 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.8.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 46ee1d7d5492acf329535e60f9a579cd0f8d399244906eb3f83e6d8b44a743d0 |
|
MD5 | 0c91a980c49058fa3fa5fd49afaabb74 |
|
BLAKE2b-256 | 5b12c539254848a8de0522413d88fee49c7b51d7bf65ebff39dce744a5ed619d |