def push_deletes(self, access_token): """ Delete objects on iNaturalist that were deleted on vespawatch """ self.w("1. Delete the nests and individuals that are deleted in VW") for obs in InatObsToDelete.objects.all(): self.w( f"Deleting iNaturalist observation #{obs.inaturalist_id}...", ending='') try: delete_observation(observation_id=obs.inaturalist_id, access_token=access_token) obs.delete() # Only delete locally if the API call succeeded except JSONDecodeError: # (temporary?) iNaturalist API issue. Just log a warning. We will try to delete the observation # at the next sync logging.warning( f'Delete observation {obs.inaturalist_id} raised a JSONDecodeError' ) except ObservationNotFound: logging.warning( f"Observation {obs.inaturalist_id} could not be deleted on iNaturalist because it doesn't exist" ) obs.delete( ) # Delete it to make sure we don't try to push this delete again self.w("OK")
def handle(self, *args, **options): self.w( "Will push our observations to iNaturalist... (the observations that originate from iNaturalist won't " "be pushed.") observations = list(Individual.from_vespawatch_objects.all()) + list( Nest.from_vespawatch_objects.all()) self.w(f"We currently have {len(observations)} pushable observations.") self.w("Getting an access token for iNaturalist...", ending="") token = get_access_token(username=settings.INAT_USER_USERNAME, password=settings.INAT_USER_PASSWORD, app_id=settings.INAT_APP_ID, app_secret=settings.INAT_APP_SECRET) self.w("OK") for obs in observations: self.w(f"Pushing our observation with id={obs.pk}...", ending="") if obs.exists_in_inaturalist: self.w("This observation was already pushed, we'll update. ", ending="") try: obs.update_at_inaturalist(access_token=token) self.w("OK") except HTTPError as exc: self.w( self.style.ERROR( "iNat returned an error: does the observation exists there and do we have " "the right to update it? Exception: ") + str(exc)) else: self.w( "This is a new observation, we'll create it at iNaturalist. ", ending="") obs.create_at_inaturalist(access_token=token) self.w("OK") self.w( "Will now ensure locally deleted vespawatch observations are also deleted at iNaturalist..." ) for obs in InatObsToDelete.objects.all(): self.w( f"Deleting iNaturalist observation #{obs.inaturalist_id}...", ending='') try: delete_observation(observation_id=obs.inaturalist_id, access_token=token) except JSONDecodeError: # (temporary?) iNaturalist API issue... pass obs.delete() self.w("OK")
def test_delete_unexisting_observation(requests_mock): """ObservationNotFound is raised if the observation doesn't exists""" requests_mock.delete("https://www.inaturalist.org/observations/24774619.json", status_code=404) with pytest.raises(ObservationNotFound): delete_observation(observation_id=24774619, access_token="valid token")
def delete_test_obs(test_obs_id, token): response = delete_observation(test_obs_id, token) # Empty response is expected print("Deleted observation") pprint(response, indent=2)
def test_delete_unexisting_observation(requests_mock): """ObservationNotFound is raised if the observation doesn't exists""" requests_mock.delete(urljoin(INAT_BASE_URL, "observations/24774619.json"), status_code=404) with pytest.raises(ObservationNotFound): delete_observation(observation_id=24774619, access_token="valid token")
def test_delete_observation(requests_mock): requests_mock.delete(urljoin(INAT_BASE_URL, "observations/24774619.json"), status_code=200) response = delete_observation(observation_id=24774619, access_token="valid token") assert response is None