def create_at_inaturalist(self, access_token, user_agent): """Creates a new observation at iNaturalist for this observation It will update the current object so self.inaturalist_id is properly set. On the other side, it will also set the vespawatch_id observation field so the observation can be found from the iNaturalist record. :param access_token: as returned by pyinaturalist.rest_api.get_access_token( """ params_only_for_create = { 'taxon_id': self.taxon.inaturalist_push_taxon_id } # TODO: with the new sync, does it still makes sense to separate the create/update parameters? params = { 'observation': { **params_only_for_create, **self._params_for_inat() } } r = create_observations(params=params, access_token=access_token, user_agent=user_agent) self.inaturalist_id = r[0]['id'] self.save() self.push_attached_pictures_at_inaturalist(access_token=access_token, user_agent=user_agent)
def create_at_inaturalist(self, access_token): """Creates a new observation at iNaturalist for this observation It will update the current object so self.inaturalist_id is properly set. On the other side, it will also set the vespawatch_id observation field so the observation can be found from the iNaturalist record. :param access_token: as returned by pyinaturalist.rest_api.get_access_token( """ # TODO: push more fields # TODO: check the push works when optional fields are missing params_only_for_create = { 'taxon_id': self.taxon.inaturalist_push_taxon_id } params = { 'observation': { **params_only_for_create, **self._params_for_inat() } } r = create_observations(params=params, access_token=access_token) self.inaturalist_id = r[0]['id'] self.save() self.push_attached_pictures_at_inaturalist(access_token=access_token)
def upload_obs(obs: Observation, token: str): logger.debug('upload_obs()') #TODO: Give the observation class a method to generate this JSON params = { 'observation': { 'taxon_id': obs.taxon_id, 'species_guess': obs.taxon_name, 'observed_on_string': str(obs.observed_on), 'time_zone': obs.tzone, 'description': obs.comment, 'tag_list': obs.tags, 'latitude': obs.coordinates[0], 'longitude': obs.coordinates[1], 'positional_accuracy': obs.geotag_accuracy, # meters, 'geoprivacy': obs.geotag_privacy, 'observation_field_values_attributes': [{ 'observation_field_id': '', 'value': '' }], }, } try: logger.info('Uploading observation for taxon {0}'.format(obs.taxon_id)) r = create_observations(params=params, access_token=token) obs.inat_id = r[0]['id'] for file in obs.photos: r = add_photo_to_observation(observation_id=obs.inat_id, file_object=open(file, 'rb'), access_token=token) except HTTPError as ex: obs.inat_result = 'Error creating observation: {0}'.format(ex) logger.error('Bad result from iNaturalist API, skipping this one') logger.exception(ex) except Exception as ex: raise else: logger.info('Success') obs.inat_result = 'ok'
def test_create_observation_fail(requests_mock): params = { "observation": { "species_guess": "Pieris rapae", # Some invalid data so the observation is rejected... "observed_on_string": (datetime.now() + timedelta(days=1)).isoformat(), "latitude": 200, } } requests_mock.post( "https://www.inaturalist.org/observations.json", json=load_sample_data("create_observation_fail.json"), status_code=422, ) with pytest.raises(HTTPError) as excinfo: create_observations(params=params, access_token="valid token") assert excinfo.value.response.status_code == 422 assert "errors" in excinfo.value.response.json() # iNat also give details about the errors
def test_create_observation(requests_mock): requests_mock.post( "https://www.inaturalist.org/observations.json", json=load_sample_data("create_observation_result.json"), status_code=200, ) params = { "observation": {"species_guess": "Pieris rapae"}, } r = create_observations(params=params, access_token="valid token") assert len(r) == 1 # We added a single one assert ( r[0]["latitude"] is None ) # We have the field, but it's none since we didn't submitted anything assert r[0]["taxon_id"] == 55626 # Pieris Rapae @ iNaturalist
time_zone, 'description': 'This is a test upload', 'tag_list': '', 'latitude': coordinates[0], 'longitude': coordinates[1], 'positional_accuracy': 50, # meters, 'observation_field_values_attributes': [{ 'observation_field_id': '', 'value': '' }], }, } r = create_observations(params=params, access_token=token) new_observation_id = r[0]['id'] from pyinaturalist.rest_api import add_photo_to_observation r = add_photo_to_observation(observation_id=new_observation_id, file_object=open(file, 'rb'), access_token=token) print("Program complete")
def upload_folder_multiple(species_folder, folder, uploaded_folder, time_zone, accuracy, user, passw, app, secret): # Makes a list of all files in the folder inside element 2 of a tuple for file in os.walk(folder): if file[0] == folder: files = file # Creates list of all the file paths for every file in the folder. file_paths = [] for file in files[2]: # All files are in files[2] file_path = files[0] + file # files[0] has the path to the folder file_paths.append(file_path) # Makes a big list of paths # This is getting a token to allow photos to be uploaded. token = get_access_token(username=user, password=passw, app_id=app, app_secret=secret) # This goes to every file, checks if it is a jpg, gets the gps coordinates, # get the time, and uploads it to iNaturalist. jpgs = [] for file in file_paths: if file[-3:].lower() == 'jpg': jpgs.append(file) try: img = PIL.Image.open(jpgs[0]) coordinates = get_lat_long(img) img.close() except: coordinates = 'No Coordinates' try: date_time = get_date(file) img.close() except: date_time = 'No Date or Time' [species, taxon] = get_taxon(species_folder) print(species) # print(coordinates) # print(date_time) # print(' the taxon is ' + str(taxon)) params = { 'observation': { 'taxon_id': taxon, 'species_guess': species, 'observed_on_string': date_time, 'time_zone': time_zone, 'description': '', 'tag_list': '', 'latitude': coordinates[0], 'longitude': coordinates[1], 'positional_accuracy': int(accuracy), # meters, 'observation_field_values_attributes': [{ 'observation_field_id': '', 'value': '' }], }, } r = create_observations(params=params, access_token=token) new_observation_id = r[0]['id'] print('Uploaded as observation #' + str(new_observation_id)) print('Uploading photos') for file in jpgs: print('uploading ' + str(file) + ' TO ' + str(new_observation_id)) r = add_photo_to_observation(observation_id=new_observation_id, file_object=open(file, 'rb'), access_token=token) folder_name = os.path.split(folder) folder1_name = os.path.split(folder_name[0]) folder2_name = os.path.split(folder1_name[0]) new_species_folder = uploaded_folder + folder2_name[1] + '/' destination = new_species_folder + folder1_name[1] if new_observation_id: try: os.mkdir(new_species_folder) except: pass try: shutil.move(folder, destination) except: print('failed file move') pass