Skip to content

feat(annotations): support create() with term/value labels#684

Merged
JWCook merged 5 commits intopyinat:mainfrom
LarytheLord:feat/annotation-create-by-label-528
Feb 28, 2026
Merged

feat(annotations): support create() with term/value labels#684
JWCook merged 5 commits intopyinat:mainfrom
LarytheLord:feat/annotation-create-by-label-528

Conversation

@LarytheLord
Copy link
Copy Markdown
Contributor

Summary

  • Add support for creating annotations by term/value labels in AnnotationController.create()
  • Keep existing ID-based behavior unchanged
  • Add clear validation errors for missing/invalid term-value input

Details

  • create() now accepts either:
    • controlled_attribute_id + controlled_value_id (existing path), or
    • term + value (new path)
  • Label input is normalized (strip() + case-insensitive match)
  • Label-based input resolves to IDs using controlled terms from GET /controlled_terms

Tests

Added/updated controller tests:

  • test_create__by_label
  • test_create__missing_term_value_pair
  • test_create__invalid_term
  • test_create__invalid_value_for_term

Validation

  • uv tool run ruff check pyinaturalist/controllers/annotation_controller.py test/controllers/test_annotation_controller.py
  • uv run pytest -q test/controllers/test_annotation_controller.py

Closes #528

@LarytheLord
Copy link
Copy Markdown
Contributor Author

Pushed a small follow-up in cdec97d to address patch coverage:

  • added a missing regression test for create() without resource_id (expects ValueError)

Local run on this branch now shows 100% coverage for pyinaturalist.controllers.annotation_controller, so this should clear the codecov/patch check on rerun.

Comment thread test/controllers/test_annotation_controller.py Outdated
Comment thread test/controllers/test_annotation_controller.py Outdated
Comment thread test/controllers/test_annotation_controller.py Outdated
Comment thread test/controllers/test_annotation_controller.py Outdated
Comment thread pyinaturalist/controllers/annotation_controller.py
@LarytheLord
Copy link
Copy Markdown
Contributor Author

LarytheLord commented Feb 28, 2026

Thanks for the review. I pushed follow-up commit 6d7acef with the requested changes:

  • switched annotation create tests to use requests_mock.post (instead of patching controller post)
  • replaced manual try/except assertions with pytest.raises
  • updated term label resolution to use AnnotationController.term_lookup cache instead of calling all()

Validation run on this branch:

  • uv run pytest test/controllers/test_annotation_controller.py (11 passed)

If this looks good, please re-review when you have a moment.

@LarytheLord
Copy link
Copy Markdown
Contributor Author

All review threads from the previous round are now addressed and marked resolved, and CI is green on the latest commit.\n\nWhen you have a chance, could you take a final re-review pass?

@JWCook JWCook added this to the v1.0 milestone Feb 28, 2026
@JWCook JWCook added the enhancement New feature or request label Feb 28, 2026
resource_id: IntOrStr,
controlled_attribute_id: int | None = None,
controlled_value_id: int | None = None,
resource_id: IntOrStr | None = None,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one more thing I noticed: resource_id is always going to be required, so let's make that a required positional parameter.

Other than that, I think this looks good!

@LarytheLord
Copy link
Copy Markdown
Contributor Author

Good catch, thanks. I pushed follow-up commit 542bc3c to make resource_id a required positional parameter in annotations.create().

What changed:

  • updated AnnotationController.create() signature so resource_id is required
  • removed the now-redundant runtime resource_id is None guard
  • updated examples/tests accordingly

Validation:

  • uv run pytest test/controllers/test_annotation_controller.py test/docs/test_signatures.py (25 passed)

@JWCook
Copy link
Copy Markdown
Member

JWCook commented Feb 28, 2026

Looks good. Thank you!

@JWCook JWCook merged commit f0d4e48 into pyinat:main Feb 28, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AnnotationController.create() - allow adding annotations by label instead of ID

2 participants