Implement issue management by lb-pno · Pull Request #2043 · Labelbox/labelbox-python

Full API Reference with Examples

Issue Categories

project = client.get_project("<PROJECT_ID>")

# Create
category = project.create_issue_category(
    name="Quality",
    description="Quality-related issues",
)

# List all
categories = project.get_issue_categories()

# Update
category = category.update(name="Renamed", description="New description")

# Delete
category.delete()

Issues

from labelbox import IssueStatus, ImageIssuePosition, VideoIssuePosition, VideoFrameRange

# Create -- minimal
issue = project.create_issue(
    content="General quality issue",
    data_row_id="<DATA_ROW_ID>",
)

# Create -- with label, category, and position
issue = project.create_issue(
    content="Bounding box is misaligned",
    data_row_id="<DATA_ROW_ID>",
    label_id="<LABEL_ID>",
    category_id=category.id,
    position=ImageIssuePosition(x=100, y=200),
)

# Also accepts DataRow/Label/IssueCategory objects directly
issue = project.create_issue(
    content="Using objects instead of IDs",
    data_row_id=data_row,       # DataRow object
    label_id=label,             # Label object
    category_id=category,       # IssueCategory object
)

# Fetch with filters (returns PaginatedCollection)
for issue in project.get_issues(status=IssueStatus.OPEN):
    print(issue.friendly_id, issue.content)

# Other available filters
project.get_issues(
    data_row_id="<DATA_ROW_ID>",
    category_id="<CATEGORY_ID>",
    created_by_ids=["<USER_ID>"],
    content="search text",
)

# Fetch single issue
issue = project.get_issue("<ISSUE_ID>")

# Update (only provided fields are changed)
issue = issue.update(content="Updated text")
issue = issue.update(category_id="<NEW_CATEGORY_ID>")

# Resolve / Reopen
issue = issue.resolve()
issue = issue.reopen()

# Lazy-loaded related objects (each makes an API call)
data_row = issue.data_row()     # Optional[DataRow]
label = issue.label()           # Optional[Label]
category = issue.category()     # Optional[IssueCategory]

# Delete single
issue.delete()

# Bulk delete
project.delete_issues(["<ISSUE_ID_1>", "<ISSUE_ID_2>"])

Comments

# Create
comment = issue.create_comment(content="I agree, this needs fixing")

# List all comments on an issue
comments = issue.comments()

# Update
comment = comment.update(content="Revised comment")

# Delete
comment.delete()

Video Position Variants

# Single frame
VideoIssuePosition(frames=[
    VideoFrameRange(start=5, end=5, x=100, y=200)
])

# Contiguous range (stationary pin)
VideoIssuePosition(frames=[
    VideoFrameRange(start=5, end=11, x=450, y=300)
])

# Contiguous range (moving pin)
VideoIssuePosition(frames=[
    VideoFrameRange(start=5, end=11, x=450, y=300, end_x=500, end_y=350)
])

# Multiple separated ranges
VideoIssuePosition(frames=[
    VideoFrameRange(start=5, end=11, x=450, y=300),
    VideoFrameRange(start=20, end=25, x=100, y=100),
])