Workspace level new methods
At the workspace level you can now search and delete images.
Sample code using both:
"""Delete all orphan images matching a workspace-level search query.
Usage:
python tests/manual/demo_search_delete.py
"""
from roboflow import Roboflow
QUERY = "project:false"
PAGE_SIZE = 100
DELETE_BATCH_SIZE = 1000
DRY_RUN = False # set to False to actually delete
WORKSPACE_SLUG = "workspace"
def main():
rf = Roboflow()
workspace = rf.workspace(WORKSPACE_SLUG)
print(f"Workspace: {workspace.url}")
print(f"Query: {QUERY}")
print(f"Dry run: {DRY_RUN}")
print()
# Collect all matching image IDs.
# When deleting (not dry run), skip continuation tokens because deleted
# images shift the result set — always re-search from page 1.
all_ids = []
token = None
while True:
page = workspace.search(
QUERY,
page_size=PAGE_SIZE,
fields=["filename"],
continuation_token=token,
)
results = page.get("results", [])
if not results:
break
total = page.get("total", "?")
all_ids.extend(img["id"] for img in results)
print(f"Found {len(all_ids)}/{total} images so far...")
token = page.get("continuationToken")
if not token:
break
print(f"\nTotal images matching '{QUERY}': {len(all_ids)}")
if not all_ids:
print("Nothing to delete.")
return
if DRY_RUN:
print("\n[DRY RUN] Would delete the above images. Set DRY_RUN=False to proceed.")
return
for i in range(0, len(all_ids), DELETE_BATCH_SIZE):
batch = all_ids[i : i + DELETE_BATCH_SIZE]
print(f"Deleting batch {i // DELETE_BATCH_SIZE + 1} ({len(batch)} images)...")
result = workspace.delete_images(batch)
print(f" deleted={result.get('deletedSources')}, skipped={result.get('skippedSources')}")
print(f"\nDone. Deleted {len(all_ids)} images.")
if __name__ == "__main__":
main()