pyinaturalist 0.19.0.dev0__tar.gz → 0.19.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/CONTRIBUTORS.md +3 -1
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/HISTORY.md +7 -1
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/PKG-INFO +8 -8
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/__init__.py +1 -1
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/constants.py +9 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/docs/model_docs.py +1 -1
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/docs/templates.py +15 -4
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/formatters.py +2 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/__init__.py +1 -1
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/checklist.py +6 -3
- pyinaturalist-0.19.0.dev0/pyinaturalist/models/photo.py → pyinaturalist-0.19.0.dev2/pyinaturalist/models/media.py +55 -21
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/observation.py +59 -4
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/taxon.py +1 -2
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/request_params.py +3 -2
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/session.py +44 -19
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/observations.py +2 -2
- pyinaturalist-0.19.0.dev2/pyinaturalist/v2/__init__.py +6 -0
- pyinaturalist-0.19.0.dev2/pyinaturalist/v2/observations.py +442 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyproject.toml +11 -11
- pyinaturalist-0.19.0.dev2/test/sample_data/get_observation_with_sounds.json +581 -0
- pyinaturalist-0.19.0.dev2/test/sample_data/get_observations_v2_full.json +407 -0
- pyinaturalist-0.19.0.dev2/test/sample_data/get_observations_v2_full.py +350 -0
- pyinaturalist-0.19.0.dev2/test/sample_data/get_observations_v2_minimal.json +11 -0
- pyinaturalist-0.19.0.dev2/test/sample_data/get_observations_v2_minimal.py +11 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data.py +2 -1
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_converters.py +4 -4
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_formatters.py +2 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_models.py +98 -1
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_session.py +16 -15
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_observations.py +8 -13
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_search.py +1 -1
- pyinaturalist-0.19.0.dev2/test/v2/test_observations_v2.py +110 -0
- pyinaturalist-0.19.0.dev0/pyinaturalist/v2/__init__.py +0 -1
- pyinaturalist-0.19.0.dev0/test/sample_data/get_observation_with_sounds.json +0 -574
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/.readthedocs.yml +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/CONTRIBUTING.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/LICENSE +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/README.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docker-compose.yml +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_static/collapsible_container.css +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_static/collapsible_container.js +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_static/colors.css +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_static/favicon.ico +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_static/pyinaturalist_logo.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_static/python-logo-green.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_static/table.css +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_templates/autosummary/module.rst_t +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_templates/autosummary_core/class.rst +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_templates/header.html +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_templates/localtoc.html +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_templates/module.rst_t +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/_templates/package.rst_t +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/automodapi.rst +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/code_of_conduct.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/conf.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/contributing.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/contributors.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/endpoints.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/examples.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/history.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-new-application-complete.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-new-application.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-identifiers.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-observers.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-page-annotated.odg +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-page-annotated.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-page.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-search-bar.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-search-filters.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-observation-species-counts.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-taxon-autocomplete.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-taxon-page.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/inat-user-login.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/open-in-vscode.svg +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/password_manager_keying.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pprint_table.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo.xcf +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_gh_preview.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_gh_preview.xcf +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_hex.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_hex.xcf +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_med.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_stacked.xcf +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_white.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/pyinaturalist_logo_white.xcf +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/python-logo-green.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/images/python-logo-green.xcf +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/index.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/pyinaturalist.controllers.rst +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/pyinaturalist.models.rst +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/reference.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/docs/user_guide.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/Data Visualizations - Matplotlib.ipynb +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/Data Visualizations - Regional Activity Report.ipynb +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/Data Visualizations - Regional Observation Stats.ipynb +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/Data Visualizations - Seaborn.ipynb +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/README.md +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/Tutorial_1_Observations.ipynb +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/Tutorial_2_Taxa.ipynb +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/Tutorial_3_Data_Visualizations.ipynb +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/__init__.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/combined_activity_stats.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/histogram_by_iconic_taxon.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/identifiers_by_month.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/observation_image_grid.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/observation_map.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/observations_by_date_and_time.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/observations_by_month.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/observations_by_quality_grade.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/observations_by_year.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/observers_by_month.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/taxa_by_month.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/total_observations_by_iconic_taxon.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/images/total_taxa_by_iconic_taxon.png +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/observation_photo_metadata.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/observations_to_gpx.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/observations_to_tsp.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/sample_data/fips_to_inat_place_ids.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/sample_data/observation_fields.parquet +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/sample_data/observations.gpx +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/sample_data/observations.tsp +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/sample_data/photo_info.html +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/sample_data/us_county_fips_codes.csv +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/examples/sample_data.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinat/__init__.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/auth.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/client.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/__init__.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/base_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/controlled_term_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/observation_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/place_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/project_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/taxon_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/controllers/user_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/converters.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/docs/__init__.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/docs/docstrings.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/docs/emoji.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/docs/signatures.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/exceptions.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/base.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/conservation_status.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/controlled_term.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/identification.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/lazy_property.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/life_list.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/message.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/observation_field.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/place.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/project.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/search.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/models/user.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/node_api.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/paginator.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/py.typed +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/rest_api.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v0/__init__.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v0/observation_fields.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v0/observations.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/__init__.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/controlled_terms.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/identifications.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/messages.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/observation_fields.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/places.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/posts.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/projects.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/search.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/taxa.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/pyinaturalist/v1/users.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/__init__.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/conftest.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/controllers/test_controlled_terms_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/controllers/test_observation_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/controllers/test_place_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/controllers/test_project_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/controllers/test_taxon_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/controllers/test_user_controller.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/docs/test_docstrings.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/docs/test_signatures.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/add_project_observation.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/create_observation_fail.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/create_observation_result.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/create_observation_v1.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_access_token.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_access_token_401.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_all_observation_identifiers_ex_results.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_all_observation_observers_ex_results.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_all_observation_species_counts_ex_results.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_all_observation_species_counts_page1.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_all_observation_species_counts_page2.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_controlled_terms.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_controlled_terms_for_taxon.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_identifications.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_identifications.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_jwt.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_messages.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_nonexistent_observation.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_2.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_fields.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_fields_page1.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_fields_page2.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_day.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_day.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_hour.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_hour.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_month.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_month.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_month_of_year.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_month_of_year.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_week.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_week.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_week_of_year.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_histogram_week_of_year.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_identifiers_ex_results.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_identifiers_node_page1.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_identifiers_node_page2.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_observers_ex_results.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_observers_node_page1.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_observers_node_page2.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_popular_field_values.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_popular_field_values.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_species_counts.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_species_counts.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_taxon_summary.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_taxon_summary_conserved.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_taxon_summary_listed.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_taxonomy.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_with_ofvs.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observation_with_quality_metrics.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations.atom +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations.csv +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations.dwc +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations.js +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations.kml +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations_by_id.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations_by_id.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations_node.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations_node_page1.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_observations_node_page2.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_places_autocomplete.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_places_autocomplete.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_places_by_id.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_places_by_id.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_places_nearby.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_places_nearby.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_posts_login.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_posts_project.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_projects.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_projects.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_projects_by_id.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_projects_by_id.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_projects_obs_fields.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_search.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_search.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_autocomplete.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_autocomplete.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_autocomplete_minified.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_by_id.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_by_id.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_by_id_conservation_statuses.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_map_layers.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_with_all_names.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_taxa_with_preferred_place.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_user_by_id.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_user_by_id.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_users_autocomplete.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/get_users_autocomplete.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/obs_image.jpg +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/obs_sound.wav +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/post_observation_photos.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/post_observation_photos_list.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/post_observation_sounds.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/post_observation_sounds_list.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/post_put_observation_field_value.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/put_projects.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/update_observation_result.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/upload_photos.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/upload_photos_and_sounds.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/sample_data/upload_sounds.json +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_auth.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_client.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_compat.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_paginator.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/test_request_params.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v0/test_observation_fields_v0.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v0/test_observations_v0.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_controlled_terms.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_identifications.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_messages.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_node_api.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_observation_fields.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_places.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_posts.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_projects.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_taxa.py +0 -0
- {pyinaturalist-0.19.0.dev0 → pyinaturalist-0.19.0.dev2}/test/v1/test_users.py +0 -0
|
@@ -3,12 +3,14 @@ Thanks to the following individuals for providing pull requests, feedback, bug r
|
|
|
3
3
|
questions, and other contributions that have helped to improve pyinaturalist:
|
|
4
4
|
|
|
5
5
|
* [AE Hamrick](https://github.com/AEHamrick)
|
|
6
|
+
* [abubelinha](https://github.com/abubelinha)
|
|
6
7
|
* [Ben Armstrong](https://github.com/synrg)
|
|
7
8
|
* [Dr. Tom August](https://github.com/AugustT)
|
|
8
9
|
* [Eduardo Ramírez](https://github.com/eduramirezh)
|
|
9
10
|
* [Felipe S Barros](https://github.com/FelipeSBarros)
|
|
10
|
-
* [Ken-ichi Ueda](https://github.com/kueda
|
|
11
|
+
* [Ken-ichi Ueda](https://github.com/kueda)
|
|
11
12
|
* [Matt Muir](https://forum.inaturalist.org/u/muir)
|
|
13
|
+
* [Nicolas Noé](https://github.com/niconoe)
|
|
12
14
|
* [Patrick Leary](https://github.com/pleary)
|
|
13
15
|
* [Peter Desmet](https://github.com/peterdesmet)
|
|
14
16
|
* [pisum](https://forum.inaturalist.org/u/pisum)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Added new **User** endpoint: `get_current_user()`
|
|
7
7
|
|
|
8
8
|
### Modified Endpoints
|
|
9
|
-
Add support for searching observations by observation fields, using a new `
|
|
9
|
+
Add support for searching observations by observation fields, using a new `observation_fields` param for the following functions:
|
|
10
10
|
* `get_observations()`
|
|
11
11
|
* `get_observation_histogram()`
|
|
12
12
|
* `get_observation_identifiers()`
|
|
@@ -14,6 +14,12 @@ Add support for searching observations by observation fields, using a new `field
|
|
|
14
14
|
* `get_observation_popular_field_values()`
|
|
15
15
|
* `get_observation_species_counts()`
|
|
16
16
|
|
|
17
|
+
### Models
|
|
18
|
+
* Add `Observation.ident_taxon_ids` dynamic property to get all identification taxon IDs (with ancestors)
|
|
19
|
+
* Add `Observation.cumulative_ids` dynamic property to calculate agreements/total community identifications
|
|
20
|
+
* Add `Sound` model for `Observation.sounds`
|
|
21
|
+
* Fix initialization of `ListedTaxon.place`
|
|
22
|
+
|
|
17
23
|
## 0.18.0 (2023-02-27)
|
|
18
24
|
|
|
19
25
|
### New Endpoints
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyinaturalist
|
|
3
|
-
Version: 0.19.0.
|
|
3
|
+
Version: 0.19.0.dev2
|
|
4
4
|
Summary: iNaturalist API client for python
|
|
5
5
|
Home-page: https://github.com/pyinat/pyinaturalist
|
|
6
6
|
License: MIT
|
|
7
7
|
Keywords: inaturalist,biodiversity,conservation,citizen-science,community-science,api,api-client,data-model,requests
|
|
8
|
-
Author:
|
|
9
|
-
Author-email:
|
|
8
|
+
Author: Jordan Cook
|
|
9
|
+
Author-email: jordan.cook.git@proton.me
|
|
10
10
|
Requires-Python: >=3.7,<4.0
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
@@ -24,13 +24,13 @@ Classifier: Typing :: Typed
|
|
|
24
24
|
Provides-Extra: all
|
|
25
25
|
Provides-Extra: docs
|
|
26
26
|
Requires-Dist: attrs (>=21.2)
|
|
27
|
-
Requires-Dist: furo (>=
|
|
27
|
+
Requires-Dist: furo (>=2023.3,<2024.0) ; extra == "docs"
|
|
28
28
|
Requires-Dist: ipython (>=7.25.0,<8.0.0) ; extra == "docs"
|
|
29
29
|
Requires-Dist: keyring (>=22.3)
|
|
30
30
|
Requires-Dist: linkify-it-py (>=1.0.1,<2.0.0) ; extra == "docs"
|
|
31
|
-
Requires-Dist: myst-parser (>=0.
|
|
32
|
-
Requires-Dist: nbsphinx (>=0.
|
|
33
|
-
Requires-Dist: platformdirs (>=2.
|
|
31
|
+
Requires-Dist: myst-parser (>=1.0,<2.0) ; extra == "docs"
|
|
32
|
+
Requires-Dist: nbsphinx (>=0.9,<0.10) ; extra == "docs"
|
|
33
|
+
Requires-Dist: platformdirs (>=2.6)
|
|
34
34
|
Requires-Dist: python-dateutil (>=2.0)
|
|
35
35
|
Requires-Dist: python-forge (>=18.6)
|
|
36
36
|
Requires-Dist: requests (>=2.22)
|
|
@@ -43,7 +43,7 @@ Requires-Dist: sphinx-automodapi (>=0.14,<0.15) ; extra == "docs"
|
|
|
43
43
|
Requires-Dist: sphinx-copybutton (>=0.5) ; extra == "docs"
|
|
44
44
|
Requires-Dist: sphinx-design (>=0.2.0) ; extra == "docs"
|
|
45
45
|
Requires-Dist: sphinxcontrib-apidoc (>=0.3,<0.4) ; extra == "docs"
|
|
46
|
-
Requires-Dist: ujson (
|
|
46
|
+
Requires-Dist: ujson (>5.0) ; extra == "all"
|
|
47
47
|
Project-URL: Documentation, https://pyinaturalist.readthedocs.io
|
|
48
48
|
Project-URL: Repository, https://github.com/pyinat/pyinaturalist
|
|
49
49
|
Description-Content-Type: text/markdown
|
|
@@ -12,10 +12,10 @@ from pyinaturalist.request_params import get_interval_ranges
|
|
|
12
12
|
from pyinaturalist.session import ClientSession, clear_cache
|
|
13
13
|
from pyinaturalist.v0 import *
|
|
14
14
|
from pyinaturalist.v1 import *
|
|
15
|
-
from pyinaturalist.v2 import *
|
|
16
15
|
|
|
17
16
|
# For disambiguation
|
|
18
17
|
from pyinaturalist.v0 import create_observation as create_observation_v0
|
|
19
18
|
from pyinaturalist.v0 import get_observations as get_observations_v0
|
|
20
19
|
from pyinaturalist.v0 import update_observation as update_observation_v0
|
|
21
20
|
from pyinaturalist.v0 import delete_observation as delete_observation_v0
|
|
21
|
+
from pyinaturalist.v2 import get_observations as get_observations_v2
|
|
@@ -196,6 +196,15 @@ SOURCES = ['places', 'projects', 'taxa', 'users']
|
|
|
196
196
|
# Endpoint-specific options for multiple choice parameters
|
|
197
197
|
V0_OBS_ORDER_BY_PROPERTIES = ['date_added', 'observed_on']
|
|
198
198
|
V1_OBS_ORDER_BY_PROPERTIES = ['created_at', 'id', 'observed_on', 'species_guess', 'votes']
|
|
199
|
+
V2_OBS_ORDER_BY_PROPERTIES = [
|
|
200
|
+
'created_at',
|
|
201
|
+
'id',
|
|
202
|
+
'observed_on',
|
|
203
|
+
'species_guess',
|
|
204
|
+
'updated_at',
|
|
205
|
+
'votes',
|
|
206
|
+
'random',
|
|
207
|
+
]
|
|
199
208
|
PROJECT_ORDER_BY_PROPERTIES = ['created', 'distance', 'featured', 'recent_posts', 'updated']
|
|
200
209
|
|
|
201
210
|
# Multiple-choice request parameters, with keys mapped to their possible choices (non-endpoint-specific)
|
|
@@ -14,7 +14,7 @@ from sphinx_autodoc_typehints import format_annotation
|
|
|
14
14
|
from pyinaturalist.constants import DOCS_DIR
|
|
15
15
|
from pyinaturalist.models import LazyProperty, get_lazy_properties
|
|
16
16
|
|
|
17
|
-
IGNORE_PROPERTIES = ['
|
|
17
|
+
IGNORE_PROPERTIES = ['_row', '_str_attrs']
|
|
18
18
|
MODEL_DOC_DIR = join(DOCS_DIR, 'models')
|
|
19
19
|
|
|
20
20
|
|
|
@@ -188,7 +188,7 @@ def _observation_v1(
|
|
|
188
188
|
verifiable: Optional[bool] = None,
|
|
189
189
|
not_id: Optional[MultiInt] = None,
|
|
190
190
|
sound_license: Optional[MultiStr] = None,
|
|
191
|
-
|
|
191
|
+
observation_fields: Optional[Union[List, Dict]] = None,
|
|
192
192
|
ofv_datatype: Optional[MultiStr] = None,
|
|
193
193
|
place_id: Optional[MultiInt] = None,
|
|
194
194
|
project_id: Optional[MultiInt] = None,
|
|
@@ -260,7 +260,7 @@ def _observation_v1(
|
|
|
260
260
|
project_id: Must be added to the project this ID or slug
|
|
261
261
|
rank: Taxon must have this rank
|
|
262
262
|
site_id: Must be affiliated with the iNaturalist network website with this ID
|
|
263
|
-
|
|
263
|
+
observation_fields: Must have these observation fields (optionally with values)
|
|
264
264
|
ofv_datatype: Must have an observation field value with this datatype
|
|
265
265
|
sound_license: Must have at least one sound with this license
|
|
266
266
|
without_taxon_id: Exclude observations of these taxa and their descendants
|
|
@@ -333,13 +333,24 @@ def _observation_v0(
|
|
|
333
333
|
on: Filter by date string
|
|
334
334
|
extra: Retrieve additional information.
|
|
335
335
|
**'projects'** returns info about the projects the observations have been added to,
|
|
336
|
-
**'
|
|
336
|
+
**'observation_fields'** returns observation field values,
|
|
337
337
|
**'observation_photos'** returns information about the photos' relationship with the
|
|
338
338
|
observation, like their order.
|
|
339
339
|
response_format: A supported response format to return
|
|
340
340
|
"""
|
|
341
341
|
|
|
342
342
|
|
|
343
|
+
# Observation params that are only in the v2 API
|
|
344
|
+
def _observation_v2(
|
|
345
|
+
fields: Optional[Union[List[str], Dict[str, Any]]] = None,
|
|
346
|
+
except_fields: Optional[List[str]] = None,
|
|
347
|
+
):
|
|
348
|
+
"""Args:
|
|
349
|
+
fields: Data fields to return in the response
|
|
350
|
+
except_fields: Data fields to exclude from the response (and include all others)
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
|
|
343
354
|
def _observation_histogram(
|
|
344
355
|
date_field: str = 'observed',
|
|
345
356
|
interval: str = 'month_of_year',
|
|
@@ -384,7 +395,7 @@ def _create_observation(
|
|
|
384
395
|
):
|
|
385
396
|
"""Args:
|
|
386
397
|
species_guess: Equivalent to the 'What did you see?' field on the observation form.
|
|
387
|
-
iNat will try to choose a single taxon based on this, but it may fail if it's
|
|
398
|
+
iNat will try to choose a single taxon based on this, but it may fail if it's ambiguous
|
|
388
399
|
taxon_id: ID of the taxon to associate with this observation
|
|
389
400
|
observed_on: Alias for ``observed_on_string``; accepts :py:class:`~datetime.datetime` objects.
|
|
390
401
|
observed_on_string: Date/time of the observation. Time zone will default to the user's
|
|
@@ -36,6 +36,7 @@ from pyinaturalist.models import (
|
|
|
36
36
|
Project,
|
|
37
37
|
ResponseOrObjects,
|
|
38
38
|
SearchResult,
|
|
39
|
+
Sound,
|
|
39
40
|
Taxon,
|
|
40
41
|
TaxonCount,
|
|
41
42
|
TaxonSummary,
|
|
@@ -130,6 +131,7 @@ UNIQUE_RESPONSE_ATTRS = {
|
|
|
130
131
|
'score': SearchResult,
|
|
131
132
|
'last_observation_id': ListedTaxon,
|
|
132
133
|
'listed_taxon': TaxonSummary,
|
|
134
|
+
'native_sound_id': Sound,
|
|
133
135
|
'count': TaxonCount,
|
|
134
136
|
'rank': Taxon,
|
|
135
137
|
'roles': User,
|
|
@@ -70,7 +70,7 @@ def upper(value) -> Optional[str]:
|
|
|
70
70
|
# Models imported in order of dependencies
|
|
71
71
|
# --------------------------------------------------------
|
|
72
72
|
|
|
73
|
-
from pyinaturalist.models.
|
|
73
|
+
from pyinaturalist.models.media import IconPhoto, Photo, Sound
|
|
74
74
|
from pyinaturalist.models.place import Place
|
|
75
75
|
from pyinaturalist.models.user import User, UserCount, UserCounts
|
|
76
76
|
from pyinaturalist.models.checklist import Checklist, EstablishmentMeans, ListedTaxon
|
|
@@ -126,7 +126,8 @@ class ListedTaxon(EstablishmentMeans):
|
|
|
126
126
|
|
|
127
127
|
@place_id.setter
|
|
128
128
|
def place_id(self, value: int):
|
|
129
|
-
self.place = Place(
|
|
129
|
+
self.place = self.place or Place()
|
|
130
|
+
self.place.id = value
|
|
130
131
|
|
|
131
132
|
@property
|
|
132
133
|
def updater_id(self) -> Optional[int]:
|
|
@@ -134,7 +135,8 @@ class ListedTaxon(EstablishmentMeans):
|
|
|
134
135
|
|
|
135
136
|
@updater_id.setter
|
|
136
137
|
def updater_id(self, value: int):
|
|
137
|
-
self.updater = User(
|
|
138
|
+
self.updater = self.updater or User()
|
|
139
|
+
self.updater.id = value
|
|
138
140
|
|
|
139
141
|
@property
|
|
140
142
|
def user_id(self) -> Optional[int]:
|
|
@@ -142,7 +144,8 @@ class ListedTaxon(EstablishmentMeans):
|
|
|
142
144
|
|
|
143
145
|
@user_id.setter
|
|
144
146
|
def user_id(self, value: int):
|
|
145
|
-
self.user = User(
|
|
147
|
+
self.user = self.user or User()
|
|
148
|
+
self.user.id = value
|
|
146
149
|
|
|
147
150
|
@property
|
|
148
151
|
def _row(self) -> TableRow:
|
|
@@ -19,13 +19,7 @@ from pyinaturalist.models import BaseModel, define_model, field
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@define_model
|
|
22
|
-
class
|
|
23
|
-
""":fa:`camera` An observation photo, based on the schema of photos from:
|
|
24
|
-
|
|
25
|
-
* `GET /observations <https://api.inaturalist.org/v1/docs/#!/Observations/get_observations>`_
|
|
26
|
-
* `GET /taxa <https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa>`
|
|
27
|
-
"""
|
|
28
|
-
|
|
22
|
+
class BaseMedia(BaseModel):
|
|
29
23
|
attribution: str = field(default=None, doc='License attribution')
|
|
30
24
|
license_code: str = field(
|
|
31
25
|
default=None,
|
|
@@ -33,6 +27,30 @@ class Photo(BaseModel):
|
|
|
33
27
|
options=ALL_LICENSES,
|
|
34
28
|
doc='Creative Commons license code',
|
|
35
29
|
)
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def ext(self) -> str:
|
|
33
|
+
"""File extension from URL"""
|
|
34
|
+
return self.url.lower().split('.')[-1].split('?')[0] # type: ignore
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def has_cc_license(self) -> bool:
|
|
38
|
+
"""Determine if this photo has a Creative Commons license"""
|
|
39
|
+
return self.license_code in CC_LICENSES
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def _str_attrs(self) -> List[str]:
|
|
43
|
+
return ['id', 'license_code', 'url']
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@define_model
|
|
47
|
+
class Photo(BaseMedia):
|
|
48
|
+
""":fa:`camera` An observation photo, based on the schema of photos from:
|
|
49
|
+
|
|
50
|
+
* `GET /observations <https://api.inaturalist.org/v1/docs/#!/Observations/get_observations>`_
|
|
51
|
+
* `GET /taxa <https://api.inaturalist.org/v1/docs/#!/Taxa/get_taxa>`
|
|
52
|
+
"""
|
|
53
|
+
|
|
36
54
|
observation_id: int = field(default=None, doc='Associated observation ID')
|
|
37
55
|
original_dimensions: Tuple[int, int] = field(
|
|
38
56
|
converter=format_dimensions, default=(0, 0), doc='Dimensions of original image'
|
|
@@ -65,21 +83,11 @@ class Photo(BaseModel):
|
|
|
65
83
|
value = value['photo']
|
|
66
84
|
return super(Photo, cls).from_json(value, **kwargs)
|
|
67
85
|
|
|
68
|
-
@property
|
|
69
|
-
def ext(self) -> str:
|
|
70
|
-
"""File extension from URL"""
|
|
71
|
-
return self.url.lower().split('.')[-1].split('?')[0]
|
|
72
|
-
|
|
73
86
|
@property
|
|
74
87
|
def dimensions_str(self) -> str:
|
|
75
88
|
"""Dimensions as a string, formatted as ``{width}x{height}``"""
|
|
76
89
|
return f'{self.original_dimensions[0]}x{self.original_dimensions[1]}'
|
|
77
90
|
|
|
78
|
-
@property
|
|
79
|
-
def has_cc_license(self) -> bool:
|
|
80
|
-
"""Determine if this photo has a Creative Commons license"""
|
|
81
|
-
return self.license_code in CC_LICENSES
|
|
82
|
-
|
|
83
91
|
@property
|
|
84
92
|
def info_url(self) -> str:
|
|
85
93
|
"""Photo info URL on iNaturalist.org"""
|
|
@@ -147,10 +155,6 @@ class Photo(BaseModel):
|
|
|
147
155
|
'URL': self.original_url,
|
|
148
156
|
}
|
|
149
157
|
|
|
150
|
-
@property
|
|
151
|
-
def _str_attrs(self) -> List[str]:
|
|
152
|
-
return ['id', 'license_code', 'url']
|
|
153
|
-
|
|
154
158
|
|
|
155
159
|
@define_model
|
|
156
160
|
class IconPhoto(Photo):
|
|
@@ -179,3 +183,33 @@ class IconPhoto(Photo):
|
|
|
179
183
|
@property
|
|
180
184
|
def _str_attrs(self) -> List[str]:
|
|
181
185
|
return ['iconic_taxon_name', 'url']
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@define_model
|
|
189
|
+
class Sound(BaseMedia):
|
|
190
|
+
file_content_type: str = field(default=None)
|
|
191
|
+
file_url: str = field(default=None)
|
|
192
|
+
native_sound_id: str = field(default=None)
|
|
193
|
+
secret_token: str = field(default=None)
|
|
194
|
+
subtype: str = field(default=None)
|
|
195
|
+
|
|
196
|
+
# Unused attributes
|
|
197
|
+
# flags: List = field(factory=list)
|
|
198
|
+
# play_local: bool = field(default=None)
|
|
199
|
+
|
|
200
|
+
# Aliases
|
|
201
|
+
@property
|
|
202
|
+
def mimetype(self) -> str:
|
|
203
|
+
return self.file_content_type
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def url(self) -> str:
|
|
207
|
+
return self.file_url
|
|
208
|
+
|
|
209
|
+
@property
|
|
210
|
+
def _row(self) -> TableRow:
|
|
211
|
+
return {
|
|
212
|
+
'ID': self.id,
|
|
213
|
+
'License': self.license_code,
|
|
214
|
+
'URL': self.url,
|
|
215
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from
|
|
2
|
+
from itertools import chain
|
|
3
|
+
from typing import Any, Dict, List, Tuple
|
|
4
|
+
from warnings import warn
|
|
3
5
|
|
|
4
6
|
from pyinaturalist.constants import (
|
|
5
7
|
ALL_LICENSES,
|
|
@@ -22,6 +24,7 @@ from pyinaturalist.models import (
|
|
|
22
24
|
ObservationFieldValue,
|
|
23
25
|
Photo,
|
|
24
26
|
ProjectObservation,
|
|
27
|
+
Sound,
|
|
25
28
|
Taxon,
|
|
26
29
|
User,
|
|
27
30
|
coordinate_pair,
|
|
@@ -40,15 +43,20 @@ class Observation(BaseModel):
|
|
|
40
43
|
:v1:`GET /observations <Observations/get_observations>`
|
|
41
44
|
"""
|
|
42
45
|
|
|
46
|
+
application: Dict = field(factory=dict, doc='Application that created the observation')
|
|
43
47
|
created_at: datetime = datetime_now_field(doc='Date and time the observation was created')
|
|
44
48
|
captive: bool = field(
|
|
45
49
|
default=None, doc='Indicates if the organism is non-wild (captive or cultivated)'
|
|
46
50
|
)
|
|
47
51
|
community_taxon_id: int = field(default=None, doc='The current community identification taxon')
|
|
52
|
+
context_geoprivacy: str = field(default=None)
|
|
53
|
+
context_taxon_geoprivacy: str = field(default=None)
|
|
54
|
+
context_user_geoprivacy: str = field(default=None)
|
|
48
55
|
description: str = field(default=None, doc='Observation description')
|
|
49
56
|
faves: List[Dict] = field(
|
|
50
57
|
factory=list, doc='Details on users who have favorited the observation'
|
|
51
58
|
)
|
|
59
|
+
flags: List[Dict] = field(factory=list)
|
|
52
60
|
geoprivacy: str = field(default=None, options=GEOPRIVACY_LEVELS, doc='Location privacy level')
|
|
53
61
|
identifications_count: int = field(default=0, doc='Total number of identifications')
|
|
54
62
|
identifications_most_agree: bool = field(
|
|
@@ -126,16 +134,19 @@ class Observation(BaseModel):
|
|
|
126
134
|
site_id: int = field(
|
|
127
135
|
default=None, doc='Site ID for iNaturalist network members, or ``1`` for inaturalist.org'
|
|
128
136
|
)
|
|
129
|
-
sounds: List[Dict] = field(factory=list, doc='Observation sound files')
|
|
130
137
|
species_guess: str = field(
|
|
131
138
|
default=None, doc="Taxon name from observer's initial identification"
|
|
132
139
|
)
|
|
133
140
|
tags: List[str] = field(factory=list, doc='Arbitrary user tags added to the observation')
|
|
141
|
+
taxon_geoprivacy: str = field(default=None)
|
|
134
142
|
updated_at: DateTime = datetime_field(doc='Date and time the observation was last updated')
|
|
135
143
|
uri: str = field(default=None, doc='Link to observation details page')
|
|
136
144
|
uuid: str = field(
|
|
137
145
|
default=None, doc='Universally unique ID; generally preferred over ``id`` where possible'
|
|
138
146
|
)
|
|
147
|
+
viewer_trusted_by_observer: bool = field(
|
|
148
|
+
default=None, doc='Observer trusts the authenticated user with access to hidden coordinates'
|
|
149
|
+
)
|
|
139
150
|
votes: List[Dict] = field(factory=list, doc='Votes on data quality assessment metrics')
|
|
140
151
|
|
|
141
152
|
# Lazy-loaded model objects
|
|
@@ -161,6 +172,9 @@ class Observation(BaseModel):
|
|
|
161
172
|
type=List[ProjectObservation],
|
|
162
173
|
doc='Details on any projects that the observation has been added to',
|
|
163
174
|
)
|
|
175
|
+
sounds: property = LazyProperty(
|
|
176
|
+
Sound.from_json_list, type=List[Sound], doc='Observation sound files'
|
|
177
|
+
)
|
|
164
178
|
taxon: property = LazyProperty(Taxon.from_json, type=Taxon, doc='Observation taxon')
|
|
165
179
|
user: property = LazyProperty(User.from_json, type=User, doc='Observer')
|
|
166
180
|
|
|
@@ -170,15 +184,16 @@ class Observation(BaseModel):
|
|
|
170
184
|
# created_at_details: Dict = field(factory=dict)
|
|
171
185
|
# created_time_zone: str = field(default=None)
|
|
172
186
|
# faves_count: int = field(default=None)
|
|
173
|
-
# flags: List = field(factory=list)
|
|
174
187
|
# geojson: Dict = field(factory=dict)
|
|
175
188
|
# id_please: bool = field(default=None)
|
|
176
189
|
# map_scale: int = field(default=None)
|
|
177
190
|
# non_owner_ids: List = field(factory=list)
|
|
191
|
+
# non_traditional_projects: property = LazyProperty(Project.from_json_list, type=List[Project])
|
|
178
192
|
# observed_on_details: Dict = field(factory=dict)
|
|
179
193
|
# observed_on_string: str = field(default=None)
|
|
180
194
|
# observation_photos: List[Photo] = field(converter=Photo.from_dict_list, factory=list)
|
|
181
195
|
# observed_time_zone: str = field(default=None)
|
|
196
|
+
# private_geojson: Dict = field(factory=dict)
|
|
182
197
|
# spam: bool = field(default=None)
|
|
183
198
|
# time_observed_at: DateTime = datetime_attr
|
|
184
199
|
# time_zone_offset: str = field(default=None)
|
|
@@ -191,9 +206,11 @@ class Observation(BaseModel):
|
|
|
191
206
|
observed_on = kwargs.pop('time_observed_at', None)
|
|
192
207
|
if not isinstance(kwargs['observed_on'], datetime) and observed_on:
|
|
193
208
|
kwargs['observed_on'] = observed_on
|
|
209
|
+
|
|
194
210
|
# Set default URL based on observation ID
|
|
195
211
|
if not kwargs.get('uri'):
|
|
196
212
|
kwargs['uri'] = f'{INAT_BASE_URL}/observations/{kwargs.get("id", "")}'
|
|
213
|
+
|
|
197
214
|
# Set identifications_count if missing
|
|
198
215
|
if kwargs.get('identifications') and not kwargs.get('identifications_count'):
|
|
199
216
|
kwargs['identifications_count'] = len(kwargs['identifications'])
|
|
@@ -201,12 +218,41 @@ class Observation(BaseModel):
|
|
|
201
218
|
|
|
202
219
|
@classmethod
|
|
203
220
|
def from_id(cls, id: int):
|
|
204
|
-
"""Lookup and create a new Observation object from an ID"""
|
|
221
|
+
"""**[Deprecated]** Lookup and create a new Observation object from an ID"""
|
|
205
222
|
from pyinaturalist.v1 import get_observation
|
|
206
223
|
|
|
224
|
+
warn(
|
|
225
|
+
DeprecationWarning(
|
|
226
|
+
'This method is deprecated; please use iNatClient.observations() instead'
|
|
227
|
+
)
|
|
228
|
+
)
|
|
207
229
|
json = get_observation(id)
|
|
208
230
|
return cls.from_json(json)
|
|
209
231
|
|
|
232
|
+
@property
|
|
233
|
+
def cumulative_ids(self) -> Tuple[int, int]:
|
|
234
|
+
"""Calculate the cumulative community ID score (agreements/total), as shown on the observation UI
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
``(agreements, total)``
|
|
238
|
+
"""
|
|
239
|
+
idents_count = 0
|
|
240
|
+
idents_agree = 0
|
|
241
|
+
ident_taxon_ids = self.ident_taxon_ids
|
|
242
|
+
|
|
243
|
+
for ident in filter(lambda i: i.current, self.identifications):
|
|
244
|
+
user_taxon_ids = ident.taxon.ancestor_ids + [ident.taxon.id]
|
|
245
|
+
if self.community_taxon_id in user_taxon_ids:
|
|
246
|
+
# Count towards total & agree:
|
|
247
|
+
if ident.taxon.id in ident_taxon_ids:
|
|
248
|
+
idents_count += 1
|
|
249
|
+
idents_agree += 1
|
|
250
|
+
else:
|
|
251
|
+
# Maverick counts against:
|
|
252
|
+
idents_count += 1
|
|
253
|
+
|
|
254
|
+
return (idents_agree, idents_count)
|
|
255
|
+
|
|
210
256
|
@property
|
|
211
257
|
def default_photo(self) -> Photo:
|
|
212
258
|
"""Get the default observation photo if any; otherwise use taxon default photo or icon"""
|
|
@@ -217,6 +263,15 @@ class Observation(BaseModel):
|
|
|
217
263
|
else:
|
|
218
264
|
return IconPhoto.from_iconic_taxon('unknown')
|
|
219
265
|
|
|
266
|
+
@property
|
|
267
|
+
def ident_taxon_ids(self) -> List[int]:
|
|
268
|
+
"""Get all taxon IDs (including ancestors) from identifications"""
|
|
269
|
+
ident_taxa = [
|
|
270
|
+
ident.taxon for ident in self.identifications if ident.taxon and ident.current
|
|
271
|
+
]
|
|
272
|
+
ident_ids = chain.from_iterable([t.ancestor_ids + [t.id] for t in ident_taxa])
|
|
273
|
+
return list(set(ident_ids))
|
|
274
|
+
|
|
220
275
|
@property
|
|
221
276
|
def _row(self) -> TableRow:
|
|
222
277
|
return {
|
|
@@ -224,10 +224,9 @@ class Taxon(BaseModel):
|
|
|
224
224
|
"""Info URL on iNaturalist.org"""
|
|
225
225
|
return f'{INAT_BASE_URL}/taxa/{self.id}'
|
|
226
226
|
|
|
227
|
-
# TODO: Experimental; not sure if I want to have API calls in model classes
|
|
228
227
|
@classmethod
|
|
229
228
|
def from_id(cls, id: int) -> 'Taxon':
|
|
230
|
-
"""Lookup and create a new Taxon object by ID"""
|
|
229
|
+
"""**[Deprecated]** Lookup and create a new Taxon object by ID"""
|
|
231
230
|
from pyinaturalist.v1 import get_taxa_by_id
|
|
232
231
|
|
|
233
232
|
warn(DeprecationWarning('This method is deprecated; please use iNatClient.taxa() instead'))
|
|
@@ -177,7 +177,8 @@ def convert_observation_field_params(params: RequestParams) -> RequestParams:
|
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
def convert_observation_field_filters(params: RequestParams) -> RequestParams:
|
|
180
|
-
|
|
180
|
+
"""Convert observation field filters from simplified format to full request params"""
|
|
181
|
+
fields = params.pop('observation_fields', None)
|
|
181
182
|
if not fields:
|
|
182
183
|
return params
|
|
183
184
|
# List of fields to filter on (any value)
|
|
@@ -357,7 +358,7 @@ def _validate_multiple_choice_param(
|
|
|
357
358
|
return True
|
|
358
359
|
if not isinstance(value, list):
|
|
359
360
|
value = [value]
|
|
360
|
-
return all(
|
|
361
|
+
return all(v in choices for v in value)
|
|
361
362
|
|
|
362
363
|
def normalize(value):
|
|
363
364
|
if not value:
|