def add_photo_to_observation( observation_id: int, file_object: BinaryIO, access_token: str, user_agent: str = None, ): """Upload a picture and assign it to an existing observation. Args: observation_id: the ID of the observation file_object: a file-like object for the picture. Example: open('/Users/nicolasnoe/vespa.jpg', 'rb') access_token: the access token, as returned by :func:`get_access_token()` user_agent: a user-agent string that will be passed to iNaturalist. """ data = {"observation_photo[observation_id]": observation_id} file_data = {"file": file_object} response = post( url="{base_url}/observation_photos".format(base_url=INAT_BASE_URL), access_token=access_token, user_agent=user_agent, data=data, files=file_data, ) return response.json()
def create_observations(params: Dict[str, Dict[str, Any]], access_token: str, user_agent: str = None) -> List[Dict[str, Any]]: """Create a single or several (if passed an array) observations). For API reference, see: https://www.inaturalist.org/pages/api+reference#post-observations Example: >>> params = {'observation': {'species_guess': 'Pieris rapae'}} >>> token = get_access_token('...') >>> create_observations(params=params, access_token=token) Args: params: access_token: the access token, as returned by :func:`get_access_token()` user_agent: a user-agent string that will be passed to iNaturalist. Returns: The newly created observation(s) in JSON format Raises: :py:exc:`requests.HTTPError`, if the call is not successful. iNaturalist returns an error 422 (unprocessable entity) if it rejects the observation data (for example an observation date in the future or a latitude > 90. In that case the exception's `response` attribute give details about the errors. TODO investigate: according to the doc, we should be able to pass multiple observations (in an array, and in renaming observation to observations, but as far as I saw they are not created (while a status of 200 is returned) """ response = post( url="{base_url}/observations.json".format(base_url=INAT_BASE_URL), json=params, access_token=access_token, user_agent=user_agent, ) response.raise_for_status() return response.json()
def create_observation( params: RequestParams = None, access_token: str = None, user_agent: str = None, **kwargs ) -> ListResponse: """Create a new observation. **API reference:** https://www.inaturalist.org/pages/api+reference#post-observations Example: >>> token = get_access_token('...') >>> create_observation( >>> access_token=token, >>> species_guess='Pieris rapae', >>> local_photos='~/observation_photos/2020_09_01_14003156.jpg', >>> observation_fields={297: 1}, # 297 is the obs. field ID for 'Number of individuals' >>> ) .. admonition:: Example Response :class: toggle .. literalinclude:: ../sample_data/create_observation_result.json :language: javascript .. admonition:: Example Response (failure) :class: toggle .. literalinclude:: ../sample_data/create_observation_fail.json :language: javascript Returns: JSON response containing the newly created observation(s) Raises: :py:exc:`requests.HTTPError`, if the call is not successful. iNaturalist returns an error 422 (unprocessable entity) if it rejects the observation data (for example an observation date in the future or a latitude > 90. In that case the exception's ``response`` attribute gives more details about the errors. """ # Accept either top-level params (like most other endpoints) # or nested {"observation": params} (like the iNat API accepts directly) if "observation" in kwargs: kwargs.update(kwargs.pop("observation")) kwargs = check_deprecated_params(params, **kwargs) kwargs = convert_observation_fields(kwargs) if "local_photos" in kwargs: kwargs["local_photos"] = ensure_file_objs(kwargs["local_photos"]) response = post( url="{base_url}/observations.json".format(base_url=INAT_BASE_URL), json={"observation": kwargs}, access_token=access_token, user_agent=user_agent, ) response.raise_for_status() return response.json()
def add_photo_to_observation( observation_id: int, photo: FileOrPath, access_token: str, user_agent: str = None, ): """Upload a local photo and assign it to an existing observation. **API reference:** https://www.inaturalist.org/pages/api+reference#post-observation_photos Example: >>> token = get_access_token('...') >>> add_photo_to_observation( >>> 1234, >>> '~/observation_photos/2020_09_01_14003156.jpg', >>> access_token=token, >>> ) .. admonition:: Example Response :class: toggle .. literalinclude:: ../sample_data/add_photo_to_observation.json :language: javascript Args: observation_id: the ID of the observation photo: An image file, file-like object, or path access_token: the access token, as returned by :func:`get_access_token()` user_agent: a user-agent string that will be passed to iNaturalist. Returns: Information about the newly created photo """ response = post( url="{base_url}/observation_photos".format(base_url=INAT_BASE_URL), access_token=access_token, data={"observation_photo[observation_id]": observation_id}, files={"file": ensure_file_obj(photo)}, user_agent=user_agent, ) return response.json()
def get_access_token(username: str, password: str, app_id: str, app_secret: str, user_agent: str = None) -> str: """ Get an access token using the user's iNaturalist username and password. You still need an iNaturalist app to do this. Example: >>> access_token = get_access_token('...') >>> headers = {"Authorization": f"Bearer {access_token}"} Args: username: iNaturalist username password: iNaturalist password app_id: iNaturalist application ID app_secret: iNaturalist application secret user_agent: a user-agent string that will be passed to iNaturalist. """ payload = { "client_id": app_id, "client_secret": app_secret, "grant_type": "password", "username": username, "password": password, } response = post( "{base_url}/oauth/token".format(base_url=INAT_BASE_URL), json=payload, user_agent=user_agent, ) try: return response.json()["access_token"] except KeyError: raise AuthenticationError( "Authentication error, please check credentials.")