Repository navigation
[ar-api] Add explicit video selection to SDK and CLI search (VID-52) - #542
Merged
Merged
Conversation
Project.search/search_all, Workspace.search/search_all and the CLI search commands could only reach images: they never sent `mediaTypes`, so the API applied its default of `["image"]` and native video Sources were undiscoverable through the SDK. Add a keyword-only `media_types` parameter to each search surface and a `--media-types` option to `roboflow search` and `roboflow image search`. Omitting it still leaves `mediaTypes` off the request body, so the existing image-only default and every existing positional signature are unchanged. The selection is forwarded through every pagination path: `Project.search_all` offset paging, `Workspace.search_all` continuation-token paging, and the CLI `--cursor` option. A shared `roboflow.util.search_utils` mirrors the API contract (non-empty list of image/video, lowercased and de-duplicated) so an invalid selection raises before any request instead of returning an opaque 400. The CLI reports it as a structured error, and rejects `--media-types` with `--export` because the export route does not accept the field. `roboflow image search` also gains `--fields`, which is what makes the signed `videoUrl` reachable from that command. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rich styles each `-` of an option name as its own span, so the literal `--media-types` never appears in `--help` output when color is enabled. The assertions passed locally (no TTY, no color) and failed on CI. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The group is still named `image`; renaming its docstring was unnecessary scope for this change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…uard Two corrections to the previous commits. `rfapi.workspace_search` took `media_types` as a positional-or-keyword parameter, so the "keyword-only everywhere" claim was only true of the higher-level SDK methods. Put it behind a bare `*`. The six pre-existing parameters keep their positions, and a test now pins both the kind and the positional order. The CLI export guard tested `--media-types` for truthiness, so an explicit but empty `--media-types ""` was falsy and fell through to the export route instead of being rejected — verified by dispatch: the old guard got as far as resolving the export dataset. Compare against `None` so any explicit value is caught, and reject the blank value on the search path too. `parse_media_types_option` also documented an empty string as meaning "use the API default" while the code raised on it. The code is right — a blank value is an explicit empty selection — so the docstring now says that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Project.search/search_all,Workspace.search/search_alland the CLI search commands could only ever reach images. None of them sent themediaTypesfield the search API accepts, so the API applied its default of["image"]and native video Sources were undiscoverable through the SDK — even though they index withmediaType: "video"and a signed video URL.This adds explicit image/video/mixed selection to those existing surfaces. It does not add a parallel video search API.
What changed
SDK — a keyword-only
media_typesparameter onProject.search/search_all,Workspace.search/search_all, andrfapi.workspace_search:CLI —
--media-typesonroboflow searchandroboflow image search:roboflow image searchalso gains--fields. Without it the signedvideoUrlis unreachable from that command, since the API only attaches it whenurlis requested.Behaviour preserved
mediaTypesoff the request body entirely, so the API default (images) applies and nothing about existing image search changes. Tests assert the field's absence, not just an image value.media_typesis keyword-only everywhere, so every existing positional call signature is untouched.--api-key→ saved/env) is unchanged.Pagination
The selection is forwarded through all three pagination paths:
Project.search_alloffset paging,Workspace.search_allcontinuation-token paging, and the CLI--cursoroption.Errors
A shared
roboflow.util.search_utilsmirrors the API contract — non-empty list ofimage/video, lowercased and de-duplicated — so an invalid selection raisesValueErrorbefore any HTTP request rather than surfacing an opaque 400:The CLI reports these as structured errors with exit code 1, and rejects
--media-typestogether with--exportbecause the search export route does not accept the field.Verification on staging
Exercised against real
api.roboflow.onewith a disposable private Action Recognition project inmodel-evaluation-workspace, holding three fresh canonical Sources (allduplicate: null): an MP4 video, a MOV video, and one image.project.search()with no selectionmedia_types=["video"]mediaType=video, signedvideoUrlon eachmedia_types=["image","video"]videoUrlwithouturlinfieldsurlon a video hitContent-Type: image/jpeg)videoUrlfetchedvideo/mp4andvideo/quicktime, sha256 matches the uploaded bytesproject.search_all(limit=1)workspace.search_all(page_size=1)--limit 1+--cursorProject.image(<searched id>)mediaType=videoAuthenticated app inspection after restoring only the owned Trash project showed both native video batches and the image on Annotate Board. Each video opened in the actual editor with its original first frame rendered (MP4: 3.000s, Frame 1/75; MOV: 3.000s, Frame 1/90), SAVED and with no segments. Dataset showed zero. No annotations were created. The project was then re-deleted through public recoverable Trash; active uncached GET returned 404, the exact Trash ID matched, and fresh workspace listing/search no longer found these fixtures.
All staging fixtures were created and deleted by this verification run. No shared or deduplicated Source was touched.
Tests
43 focused tests (
tests/test_search_media_types.py,tests/cli/test_search_media_types.py) covering the validator, both SDK surfaces, the adapter, both pagination paths, both CLI paths, and the image-default regression.Full current-head suite: 1162 tests run (1 skipped); 14 exact-head CheckRuns passed, plus the green pre-commit.ci status (15 green statuses total).
ruff checkandmypyclean.Scope notes
mediaTypes, so--exportrejects it rather than silently ignoring it. Export-side video support is out of scope here.like_image) and annotationformat=have no video equivalent and are not presented as video support.roboflow image search -pcontinues to pass the API response through verbatim, so it does not echomediaTypesthe way the workspace path does. That is pre-existing behaviour for that path and is left unchanged.