Example #1
0
def test_create_observation_fail(requests_mock):
    params = {
        "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(
        urljoin(INAT_BASE_URL, "observations.json"),
        json=load_sample_data("create_observation_fail.json"),
        status_code=422,
    )

    with pytest.raises(HTTPError) as excinfo:
        create_observation(access_token="valid token", **params)
    assert excinfo.value.response.status_code == 422
    assert "errors" in excinfo.value.response.json()  # iNat also give details about the errors
Example #2
0
def test_create_observation(requests_mock):
    requests_mock.post(
        urljoin(INAT_BASE_URL, "observations.json"),
        json=load_sample_data("create_observation_result.json"),
        status_code=200,
    )

    r = create_observation(species_guess="Pieris rapae", access_token="valid token")
    assert len(r) == 1  # We added a single one
    assert r[0]["latitude"] is None
    assert r[0]["taxon_id"] == 55626  # Pieris Rapae @ iNaturalist
Example #3
0
def create_test_obs(token):
    response = create_observation(
        taxon_id=54327,
        observed_on_string=datetime.now().isoformat(),
        description=
        "This is a test observation used by pyinaturalist, and will be deleted shortly.",
        tag_list="wasp, Belgium",
        latitude=50.647143,
        longitude=4.360216,
        positional_accuracy=50,
        geoprivacy="open",
        access_token=token,
        observation_fields={297: 1},
    )
    test_obs_id = response[0]["id"]
    print("Created new observation: {}".format(test_obs_id))

    obs = get_observation(test_obs_id)
    print("Fetched new observation:")
    pprint(obs, indent=2)
    return test_obs_id
Example #4
0
def test_create_observation__local_photo(post, ensure_file_objs):
    create_observation(access_token="token", local_photos="photo.jpg")

    # Make sure local_photos is replaced with the output of ensure_file_objs
    called_params = post.call_args[1]["json"]["observation"]
    assert called_params["local_photos"] == ensure_file_objs.return_value
Example #5
0
def inaturalist_api():
    json_data = json.loads(request.data)
    print(json_data)
    utc_key = json_data['utc_key']
    print(f'utc_key: {utc_key}')
    if utc_key is None:
        return
    print(f'key: {utc_key}')
    conn = sqlite3.connect(DB_PATH, timeout=15)
    query = '''SELECT datetime, file_name, prediction, true_label, inaturalist_id
               FROM results 
               WHERE utc_datetime = ?
               LIMIT 1;'''
    c = conn.cursor()
    c.execute(query, (utc_key, ))
    row = c.fetchone()
    if row is None:
        return
    else:
        obs_timestamp = row[0]
        img_fn = row[1]
        pred_label = row[2]
        true_label = row[3]
        existing_inat_id = row[4]
    if true_label is not None:
        obs_label = true_label
    else:
        obs_label = pred_label

    # Get a token for the inaturalist API
    token = get_access_token(
        username=INAT_USERNAME,
        password=INAT_PASSWORD,
        app_id=INAT_APP_ID,
        app_secret=INAT_APP_SECRET,
    )

    obs_file_name = f'{DATA_DIR}/imgs/{img_fn}'

    # Upload the observation to iNaturalist
    if existing_inat_id is None:
        # Check if there's an existing inat id within 5 minutes of this image
        # upload this image to that observation if so.
        window_timestamp = dt.datetime.fromisoformat(utc_key) - dt.timedelta(
            minutes=10)
        window_timestamp = window_timestamp.strftime(dt_fmt)
        query = '''SELECT inaturalist_id
                   FROM results 
                   WHERE utc_datetime <= :utc_dt
                   AND utc_datetime >= :prev_dt
                   AND inaturalist_id IS NOT NULL
                   AND (true_label = :lab OR (true_label IS NULL AND prediction = :lab))
                   ORDER BY utc_datetime DESC
                   LIMIT 1;'''
        c.execute(query, {
            'utc_dt': utc_key,
            'prev_dt': window_timestamp,
            'lab': obs_label
        })
        row = c.fetchone()
        if row is None or row[0] is None:
            response = create_observation(
                taxon_id=species_map[obs_label]['taxa_id'],
                observed_on_string=obs_timestamp,
                time_zone='Mountain Time (US & Canada)',
                description=
                'Birb Cam image upload: https://github.com/evjrob/birbcam',
                tag_list=f'{obs_label}, Canada',
                latitude=INAT_LATITUDE,
                longitude=INAT_LONGITUDE,
                positional_accuracy=INAT_POSITIONAL_ACCURACY,  # meters,
                access_token=token,
            )
            inat_observation_id = response[0]['id']
            print(
                f'No iNaturalist id found in previous ten minutes, creating new row with id {inat_observation_id}.'
            )
        else:
            inat_observation_id = row[0]
            print(
                f'Found iNaturalist id in previous ten minutes, adding to id {inat_observation_id}.'
            )
        # Upload the image captured
        r = add_photo_to_observation(
            inat_observation_id,
            access_token=token,
            photo=obs_file_name,
        )
        # Update the row in the database with the inaturalist id
        c.execute("UPDATE results SET inaturalist_id=? WHERE utc_datetime=?;",
                  (inat_observation_id, utc_key))
    else:
        # This image had already been uploaded, we do not want to upload it again
        inat_observation_id = existing_inat_id
        print(
            f'Found existing iNaturalist id {inat_observation_id} for row, skipping.'
        )

    conn.commit()
    conn.close()
    return jsonify({'inat_id': inat_observation_id})